From 60f59df2ba327a8cd96ad60fa1ff3b6f757dc8b4 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 15 Sep 2014 19:11:30 +0200 Subject: [PATCH 01/37] feature #2911:vCenter driver --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 src/vmm_mad/remotes/vcenter/vcenter_driver.rb diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb new file mode 100644 index 0000000000..e4487dca23 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -0,0 +1,149 @@ +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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) + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" +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' + +require 'rbvmomi' +require 'yaml' +require 'opennebula' + +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 + + def initialize(hid) + begin + @client = ::OpenNebula::Client.new() + rescue Exception => e + raise "Error initializing OpenNebula client: #{e.message }" + end + + @host = ::OpenNebula::Host.new_with_id(hid,@client) + rc = @host.info + + if ::OpenNebula.is_error?(rc) + raise "Error getting host information: #{rc.message}" + end + + @vc_user = @host["TEMPLATE/VCENTER_USER"] + @vc_pass = @host["TEMPLATE/VCENTER_PASSWORD"] + @vc_host = @host["TEMPLATE/VCENTER_HOST"] + + begin + @vc_client = RbVmomi::VIM.connect(:host => @vc_host, :user => @vc_user, + :password => @vc_pass, :insecure => true) + @vc_root = @vc_client.root + rescue Exception => e + raise "Error connecting to #{@vc_host}: #{e.message}" + end + + # Look for the corresponding ClusterComputeResource + @vc_root.childEntity.each {|dc| + clusters = dc.hostFolder.childEntity.grep(RbVmomi::VIM::ClusterComputeResource) + clusters.each{|cl| + if @host.name == cl.name + @cluster = cl + break + end + } + } + end + + ############################################################################ + # Generate an OpenNebula monitor string for this host. Reference: + # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/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 << "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 << "\n" + end + + def monitor_host_systems + vc.cluster.host.each{|h| + if h.runtime.connectionState == "connected" + + else + + end + } + end + +end +end From 4c230370ddc14a6b3b85d15f81eda455d1c6a208 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 15 Sep 2014 21:21:03 +0200 Subject: [PATCH 02/37] feature #2911: Host System information --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index e4487dca23..29c785547d 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -135,15 +135,48 @@ class VCenterHost < ::OpenNebula::Host str_info << "USEDMEMORY=" << (total_mem - free_mem).to_s << "\n" 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 - vc.cluster.host.each{|h| - if h.runtime.connectionState == "connected" + host_info = "" - else + cluster.host.each{|h| + next if h.runtime.connectionState != "connected" - end + 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 << "HOST=[" + 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 << "TOTALCPU=" << total_cpu.to_s << "," + host_info << "USEDCPU=" << used_cpu.to_s << "," + host_info << "FREECPU=" << free_cpu.to_s << "," + host_info << "TOTALMEMORY=" << total_memory.to_s << "," + host_info << "USEDMEMORY=" << used_memory.to_s << "," + host_info << "FREEMEMORY=" << free_memory.to_s + host_info << "]\n" } - end + return host_info + end end end From af23056133431c2e51d799b265e93828e6223f7a Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Thu, 18 Sep 2014 14:02:56 +0200 Subject: [PATCH 03/37] Feature #2911: Fist prototype vCenter driver --- src/im_mad/remotes/vcenter.d/vcenter.rb | 47 ++++++++ src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 108 +++++++++++++++++- 2 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 src/im_mad/remotes/vcenter.d/vcenter.rb diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/vcenter.rb new file mode 100644 index 0000000000..c593386c6a --- /dev/null +++ b/src/im_mad/remotes/vcenter.d/vcenter.rb @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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 + +$: << "../../vmm/vcenter/" + +require 'vcenter_driver' + +host_id = ARGV[0] + +if !host_id + exit -1 +end + +vcenter_host = VCenterDriver::VCenterHost.new(host_id) + +cluster_info = vcenter_host.monitor_cluster + +cluster_info << vcenter_host.monitor_host_systems + +vm_monitor_info = vcenter_host.monitor_vms +cluster_info << "\nVM_POLL=YES" +cluster_info << "#{vm_monitor_info}" if !vm_monitor_info.empty? + +puts cluster_info diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 29c785547d..9caf074cae 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -24,7 +24,6 @@ if !ONE_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) - RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" else BIN_LOCATION = ONE_LOCATION + "/bin" if !defined?(BIN_LOCATION) LIB_LOCATION = ONE_LOCATION + "/lib" if !defined?(LIB_LOCATION) @@ -132,7 +131,7 @@ class VCenterHost < ::OpenNebula::Host # 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 << "\n" + str_info << "USEDMEMORY=" << (total_mem - free_mem).to_s end ############################################################################ @@ -162,7 +161,7 @@ class VCenterHost < ::OpenNebula::Host used_memory = stats.overallMemoryUsage*1024 free_memory = total_memory - used_memory - host_info << "HOST=[" + host_info << "\nHOST=[" host_info << "STATE=on," host_info << "HOSTNAME=\"" << h.name.to_s << "\"," host_info << "MODELNAME=\"" << hw.cpuModel.to_s << "\"," @@ -173,10 +172,111 @@ class VCenterHost < ::OpenNebula::Host host_info << "TOTALMEMORY=" << total_memory.to_s << "," host_info << "USEDMEMORY=" << used_memory.to_s << "," host_info << "FREEMEMORY=" << free_memory.to_s - host_info << "]\n" + host_info << "]" } return host_info end + + def monitor_vms + str_info = "" + @cluster.resourcePool.vm.each { |v| + name = v.name + number = -1 + number = name.split('-').last if (name =~ /^one-\d*$/) + + vm = VCenterVm.new(v) + vm.monitor + + str_info << "\nVM = [" + str_info << "ID=#{number}," + str_info << "DEPLOY_ID=\"#{name}\"," + str_info << "POLL=\"#{vm.info}\"]" + } + + return str_info + end +end + +################################################################################ +# This class is a high level abstraction of a VI VirtualMachine class with +# OpenNebula semantics. +################################################################################ + +class VCenterVm + ######################################################################## + # Creates a new VIVm using a RbVmomi::VirtualMachine object + # @param vm_vi [RbVmomi::VirtualMachine] it will be used if not nil + ######################################################################## + def initialize(vm_vi) + @vm = vm_vi + + @used_cpu = 0 + @used_memory = 0 + + @net_rx = 0 + @net_tx = 0 + end + + ######################################################################## + # Initialize the vm monitor information + ######################################################################## + def monitor + @summary = @vm.summary + @state = state_to_c(@summary.runtime.powerState) + + if @state != 'a' + @used_cpu = 0 + @used_memory = 0 + + @net_rx = 0 + @net_tx = 0 + + return + end + + @used_memory = @summary.quickStats.hostMemoryUsage * 1024 + + host = @vm.runtime.host + cpuMhz = 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 + end + + ######################################################################## + # Generates a OpenNebula IM Driver valid string with the monitor info + ######################################################################## + def info + return 'STATE=d' if @state == 'd' + + str_info = "" + + str_info << "STATE=" << @state << " " + str_info << "USEDCPU=" << @used_cpu.to_s << " " + str_info << "USEDMEMORY="<< @used_memory.to_s << " " + str_info << "NETRX=" << @net_rx.to_s << " " + str_info << "NETTX=" << @net_tx.to_s + end + +private + + ######################################################################## + # Converts the VI string state to OpenNebula state convention + ######################################################################## + def state_to_c(state) + case state + when 'poweredOn' + 'a' + when 'suspended' + 'p' + else + 'd' + end + end end end From caf27cf9d79757e69dc146dca3e375b540b8c96e Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 19 Sep 2014 10:48:42 +0200 Subject: [PATCH 04/37] Feature #2911: Add deploy functionality --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 9caf074cae..97aef7b8e1 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -119,6 +119,7 @@ class VCenterHost < ::OpenNebula::Host str_info = "" # System + str_info << "HYPERVISOR=vcenter\n" str_info << "TOTALHOST=" << summary.numHosts.to_s << "\n" str_info << "AVAILHOST=" << summary.numEffectiveHosts.to_s << "\n" @@ -218,6 +219,82 @@ class VCenterVm @net_tx = 0 end + def self.deploy(host, xml_text, vmid) + + xml = REXML::Document.new xml_text + + pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") + + if pcs.nil? + STDERR.puts("Cannot find VCenter element in VM template ") + exit(-1) + end + + template = pcs.find { |t| + type = t.elements["TYPE"] + !type.nil? && type.text.downcase == "vcenter" + } + + if !template + STDERR.puts("Cannot find VCenter element in VM template ") + exit(-1) + end + + uuid = template.elements["VM_TEMPLATE"] + + if uuid.nil? + STDERR.puts("Cannot find VM_TEMPLATE in VCenter element.") + exit(-1) + end + + uuid = uuid.text + + begin + client = ::OpenNebula::Client.new() + rescue Exception => e + raise "Error initializing OpenNebula client: #{e.message }" + end + + vm = ::OpenNebula::VirtualMachine.new_with_id(vmid, client) + rc = vm.info + + if ::OpenNebula.is_error?(rc) + raise "Error getting host information: #{rc.message}" + end + + hid = vm["HISTORY_RECORDS/HISTORY/HID"] + + vc = VCenterHost.new(hid) + + vc_template = "" + used_dc = "" + + # Look for the wanted VM Template + vc.vc_root.childEntity.each {|dc| + vms = dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) + vms.each{|v| + if v.config.uuid == uuid + used_dc = dc + vc_template = v + break + end + } + } + + relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( + :diskMoveType => :moveChildMostDiskBacking, + :pool => vc_template.runtime.host.parent.resourcePool) + + clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(:location => relocate_spec, + :powerOn => true, :template => false) + + rc = vc_template.CloneVM_Task( + :folder => vc_template.parent, :name => "one-#{vmid}", + :spec => clone_spec).wait_for_completion + + rc.config.uuid + end + ######################################################################## # Initialize the vm monitor information ######################################################################## From f422f0f7954cc59715ef672a9e22271bc14f30d4 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 19 Sep 2014 10:49:37 +0200 Subject: [PATCH 05/37] Feature #2911: Add deploy script for vcenter --- src/vmm_mad/remotes/vcenter/deploy | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/vmm_mad/remotes/vcenter/deploy diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy new file mode 100644 index 0000000000..af738f359b --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -0,0 +1,42 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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' + +dfile = ARGV[0] +host = ARGV[1] +id = ARGV[2] + +vcenter_vm = VCenterDriver::VCenterVm.new + +vcenter_vm.deploy + +puts vmware_drv.deploy(dfile, id) + +exit 0 From 2f3551ebb9368d2174a621af50cdfe3e2a4d2bf4 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 19 Sep 2014 10:52:30 +0200 Subject: [PATCH 06/37] feature #2911: New connection class for VCenter and OpenNebula --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 140 ++++++++++++------ 1 file changed, 98 insertions(+), 42 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 97aef7b8e1..0c125f986a 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -42,6 +42,86 @@ require 'opennebula' 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 + + ############################################################################ + # Initializr the VIClient, and creates an OpenNebula client + # @param hid [Integer] The OpenNebula host id with VCenter attributes + ############################################################################ + def initialize(hid) + begin + @one = ::OpenNebula::Client.new() + rescue Exception => e + raise "Error initializing OpenNebula client: #{e.message}" + end + + @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 + + @user = @one_host["TEMPLATE/VCENTER_USER"] + @pass = @one_host["TEMPLATE/VCENTER_PASSWORD"] + @host = @one_host["TEMPLATE/VCENTER_HOST"] + + connection = { + :host => @host, + :user => @user, + :password => @pass, + :insecure => true + } + + begin + @vim = RbVmomi::VIM.connect(connection) + rescue Exception => e + raise "Error connecting to #{@host}: #{e.message}" + end + + @root = @vim.root + + @cluster = nil + @resource_pool = nil + end + + + # The associated resource pool for this connection + def resource_pool + return @resource_pool if !@resource_pool.nil? + + cl = cluster + + @resource_pool = cl.resourcePool if !cl.nil? + + return @resource_pool + end + + + # The associated cluster for this connection + def cluster + return @cluster if !@cluster.nil? + + @root.childEntity.each {|dc| + ccrs = dc.hostFolder.childEntity.grep(RbVmomi::VIM::ClusterComputeResource) + next if ccrs.nil? + + @cluster = ccrs.find{ |ccr| + @host.name == ccr.name + } + } + + return @cluster + 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 @@ -50,42 +130,16 @@ module VCenterDriver class VCenterHost < ::OpenNebula::Host attr_reader :vc_client, :vc_root, :cluster, :host, :client - def initialize(hid) - begin - @client = ::OpenNebula::Client.new() - rescue Exception => e - raise "Error initializing OpenNebula client: #{e.message }" - end + ############################################################################ + # 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 - @host = ::OpenNebula::Host.new_with_id(hid,@client) - rc = @host.info - - if ::OpenNebula.is_error?(rc) - raise "Error getting host information: #{rc.message}" - end - - @vc_user = @host["TEMPLATE/VCENTER_USER"] - @vc_pass = @host["TEMPLATE/VCENTER_PASSWORD"] - @vc_host = @host["TEMPLATE/VCENTER_HOST"] - - begin - @vc_client = RbVmomi::VIM.connect(:host => @vc_host, :user => @vc_user, - :password => @vc_pass, :insecure => true) - @vc_root = @vc_client.root - rescue Exception => e - raise "Error connecting to #{@vc_host}: #{e.message}" - end - - # Look for the corresponding ClusterComputeResource - @vc_root.childEntity.each {|dc| - clusters = dc.hostFolder.childEntity.grep(RbVmomi::VIM::ClusterComputeResource) - clusters.each{|cl| - if @host.name == cl.name - @cluster = cl - break - end - } - } + @resource_pool = client.resource_pool end ############################################################################ @@ -146,7 +200,7 @@ class VCenterHost < ::OpenNebula::Host def monitor_host_systems host_info = "" - cluster.host.each{|h| + @cluster.host.each{|h| next if h.runtime.connectionState != "connected" summary = h.summary @@ -181,12 +235,12 @@ class VCenterHost < ::OpenNebula::Host def monitor_vms str_info = "" - @cluster.resourcePool.vm.each { |v| + @resource_pool.vm.each { |v| name = v.name number = -1 number = name.split('-').last if (name =~ /^one-\d*$/) - vm = VCenterVm.new(v) + vm = VCenterVm.new(v, @client) vm.monitor str_info << "\nVM = [" @@ -209,8 +263,9 @@ class VCenterVm # Creates a new VIVm using a RbVmomi::VirtualMachine object # @param vm_vi [RbVmomi::VirtualMachine] it will be used if not nil ######################################################################## - def initialize(vm_vi) - @vm = vm_vi + def initialize(vm_vi, client) + @vm = vm_vi + @client = client @used_cpu = 0 @used_memory = 0 @@ -314,8 +369,9 @@ class VCenterVm @used_memory = @summary.quickStats.hostMemoryUsage * 1024 - host = @vm.runtime.host - cpuMhz = host.summary.hardware.cpuMhz.to_f + host = @vm.runtime.host + cpuMhz = 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 From 880dac14014ad200039956dae97e031b6fae5cbc Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 19 Sep 2014 11:28:35 +0200 Subject: [PATCH 07/37] Feature #2911: Polising refactor --- src/im_mad/remotes/vcenter.d/vcenter.rb | 7 ++++--- src/vmm_mad/remotes/vcenter/deploy | 13 +++++++------ src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 8 +++++--- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/vcenter.rb index c593386c6a..2d71377083 100644 --- a/src/im_mad/remotes/vcenter.d/vcenter.rb +++ b/src/im_mad/remotes/vcenter.d/vcenter.rb @@ -34,13 +34,14 @@ if !host_id exit -1 end -vcenter_host = VCenterDriver::VCenterHost.new(host_id) +vi_client = VCenterDriver::VIClient.new host_id + +vcenter_host = VCenterDriver::VCenterHost.new vi_client cluster_info = vcenter_host.monitor_cluster - cluster_info << vcenter_host.monitor_host_systems - vm_monitor_info = vcenter_host.monitor_vms + cluster_info << "\nVM_POLL=YES" cluster_info << "#{vm_monitor_info}" if !vm_monitor_info.empty? diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index af738f359b..7a2a79c35f 100644 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -33,10 +33,11 @@ dfile = ARGV[0] host = ARGV[1] id = ARGV[2] -vcenter_vm = VCenterDriver::VCenterVm.new +begin + puts VCenterDriver::VCenterVm.deploy dfile + exit 0 +rescue Exception => e + STDERR.puts "Deploy of VM #{id} on host #{host} with #{dfile} failed \ + due to #{e.message}" +end -vcenter_vm.deploy - -puts vmware_drv.deploy(dfile, id) - -exit 0 diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 0c125f986a..cd0aeb054d 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -114,8 +114,10 @@ class VIClient next if ccrs.nil? @cluster = ccrs.find{ |ccr| - @host.name == ccr.name + @one_host.name == ccr.name } + + break if @cluster } return @cluster @@ -263,7 +265,7 @@ class VCenterVm # Creates a new VIVm using a RbVmomi::VirtualMachine object # @param vm_vi [RbVmomi::VirtualMachine] it will be used if not nil ######################################################################## - def initialize(vm_vi, client) + def initialize(client, vm_vi ) @vm = vm_vi @client = client @@ -274,7 +276,7 @@ class VCenterVm @net_tx = 0 end - def self.deploy(host, xml_text, vmid) + def self.deploy(xml_text) xml = REXML::Document.new xml_text From bde46c78c08ab8ac6bc4dd04468e18ba9d99a4b2 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 19 Sep 2014 11:36:24 +0200 Subject: [PATCH 08/37] feature #2911: Make use of new VIClient class --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 118 +++++++----------- 1 file changed, 45 insertions(+), 73 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index cd0aeb054d..e5196dfa43 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -49,7 +49,7 @@ module VCenterDriver # For the VCenter driver each OpenNebula host represents a VCenter cluster ################################################################################ class VIClient - attr_reader :vim, :one, :root + attr_reader :vim, :one, :root, :cluster ############################################################################ # Initializr the VIClient, and creates an OpenNebula client @@ -86,42 +86,39 @@ class VIClient raise "Error connecting to #{@host}: #{e.message}" end - @root = @vim.root - - @cluster = nil - @resource_pool = nil - end - - - # The associated resource pool for this connection - def resource_pool - return @resource_pool if !@resource_pool.nil? - - cl = cluster - - @resource_pool = cl.resourcePool if !cl.nil? - - return @resource_pool - end - - - # The associated cluster for this connection - def cluster - return @cluster if !@cluster.nil? + @root = @vim.root @root.childEntity.each {|dc| ccrs = dc.hostFolder.childEntity.grep(RbVmomi::VIM::ClusterComputeResource) + next if ccrs.nil? @cluster = ccrs.find{ |ccr| @one_host.name == ccr.name } - break if @cluster + if @cluster + @dc = dc + break + end } - return @cluster + if @dc.nil? || @cluser.nil? + raise "Cannot find DataCenter or ClusterComputeResource for host." + end end + + # The associated resource pool for this connection + def resource_pool + return @cluster.resourcePool + end + + def find_vm_template(uuid) + vms = @dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) + + return vms.find{ |v| v.config.uuid == uuid } + end + end ################################################################################ @@ -261,7 +258,7 @@ end ################################################################################ class VCenterVm - ######################################################################## + ############################################################################ # Creates a new VIVm using a RbVmomi::VirtualMachine object # @param vm_vi [RbVmomi::VirtualMachine] it will be used if not nil ######################################################################## @@ -276,80 +273,55 @@ class VCenterVm @net_tx = 0 end + ############################################################################ + # Deploys a VM + # @param host the hostname of the OpenNebula host to deploy the VM + # @xml_test the XML of the + ############################################################################ def self.deploy(xml_text) xml = REXML::Document.new xml_text pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") - if pcs.nil? - STDERR.puts("Cannot find VCenter element in VM template ") - exit(-1) - end + raise "Cannot find VCenter element in VM template." if pcs.nil? template = pcs.find { |t| type = t.elements["TYPE"] !type.nil? && type.text.downcase == "vcenter" } - if !template - STDERR.puts("Cannot find VCenter element in VM template ") - exit(-1) - end + raise "Cannot find VCenter element in VM template." if template.nil? uuid = template.elements["VM_TEMPLATE"] - - if uuid.nil? - STDERR.puts("Cannot find VM_TEMPLATE in VCenter element.") - exit(-1) - end + + raise "Cannot find VM_TEMPLATE in VCenter element." if uuid.nil? uuid = uuid.text - begin - client = ::OpenNebula::Client.new() - rescue Exception => e - raise "Error initializing OpenNebula client: #{e.message }" - end + hid = xml.root.elements["//HISTORY_RECORDS/HISTORY/HID"] - vm = ::OpenNebula::VirtualMachine.new_with_id(vmid, client) - rc = vm.info + raise "Cannot find host id in deployment file history." if hid.nil? - if ::OpenNebula.is_error?(rc) - raise "Error getting host information: #{rc.message}" - end + connection = VIClient.new(hid) - hid = vm["HISTORY_RECORDS/HISTORY/HID"] - - vc = VCenterHost.new(hid) - - vc_template = "" - used_dc = "" - - # Look for the wanted VM Template - vc.vc_root.childEntity.each {|dc| - vms = dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) - vms.each{|v| - if v.config.uuid == uuid - used_dc = dc - vc_template = v - break - end - } - } + vc_template= connection.find_vm_template(uuid) relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( :diskMoveType => :moveChildMostDiskBacking, - :pool => vc_template.runtime.host.parent.resourcePool) + :pool => connection.resource_pool) - clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(:location => relocate_spec, - :powerOn => true, :template => false) + clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec( + :location => relocate_spec, + :powerOn => true, + :template => false) rc = vc_template.CloneVM_Task( - :folder => vc_template.parent, :name => "one-#{vmid}", - :spec => clone_spec).wait_for_completion + :folder => vc_template.parent, + :name => "one-#{vmid}", + :spec => clone_spec).wait_for_completion - rc.config.uuid + return rc.config.uuid end ######################################################################## From 89eb4299220b38e539f5d15de4875fb2132d998d Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 19 Sep 2014 12:25:10 +0200 Subject: [PATCH 09/37] Feature #2911: Fix deploy action for vcenter --- src/vmm_mad/remotes/vcenter/deploy | 6 +++--- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index 7a2a79c35f..5282118339 100644 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -34,10 +34,10 @@ host = ARGV[1] id = ARGV[2] begin - puts VCenterDriver::VCenterVm.deploy dfile + puts VCenterDriver::VCenterVm.deploy File.read(dfile) exit 0 rescue Exception => e - STDERR.puts "Deploy of VM #{id} on host #{host} with #{dfile} failed \ - due to #{e.message}" + STDERR.puts "Deploy of VM #{id} on host #{host} with #{dfile} failed " + + "due to \"#{e.message}\"" end diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index e5196dfa43..f53734b4ae 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -103,7 +103,7 @@ class VIClient end } - if @dc.nil? || @cluser.nil? + if @dc.nil? || @cluster.nil? raise "Cannot find DataCenter or ClusterComputeResource for host." end end @@ -239,7 +239,7 @@ class VCenterHost < ::OpenNebula::Host number = -1 number = name.split('-').last if (name =~ /^one-\d*$/) - vm = VCenterVm.new(v, @client) + vm = VCenterVm.new(@client, v) vm.monitor str_info << "\nVM = [" @@ -299,13 +299,15 @@ class VCenterVm uuid = uuid.text + vmid = xml.root.elements["/VM/ID"].text + hid = xml.root.elements["//HISTORY_RECORDS/HISTORY/HID"] raise "Cannot find host id in deployment file history." if hid.nil? - connection = VIClient.new(hid) + connection = VIClient.new(hid) - vc_template= connection.find_vm_template(uuid) + vc_template = connection.find_vm_template(uuid) relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( :diskMoveType => :moveChildMostDiskBacking, From d69a1aab35ec3c057b3534fd091af797ce30a388 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 19 Sep 2014 12:37:26 +0200 Subject: [PATCH 10/37] Feature #2911: Add PUBLIC CLOUD to vCenter hosts --- 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 f53734b4ae..61f9a213ba 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -173,6 +173,7 @@ 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 e551bdf49d959870b736423be8a6cfb0657c8600 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 19 Sep 2014 13:12:41 +0200 Subject: [PATCH 11/37] feature #2911b: New constructor for VIConnection --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 100 +++++++++++++----- 1 file changed, 73 insertions(+), 27 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 61f9a213ba..222e311f9d 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -52,15 +52,13 @@ class VIClient attr_reader :vim, :one, :root, :cluster ############################################################################ - # Initializr the VIClient, and creates an OpenNebula client + # Initializr 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) - begin - @one = ::OpenNebula::Client.new() - rescue Exception => e - raise "Error initializing OpenNebula client: #{e.message}" - end + + initialize_one @one_host = ::OpenNebula::Host.new_with_id(hid, @one) rc = @one_host.info @@ -69,38 +67,25 @@ class VIClient raise "Error getting host information: #{rc.message}" end - @user = @one_host["TEMPLATE/VCENTER_USER"] - @pass = @one_host["TEMPLATE/VCENTER_PASSWORD"] - @host = @one_host["TEMPLATE/VCENTER_HOST"] - connection = { - :host => @host, - :user => @user, - :password => @pass, - :insecure => true + :host => @one_host["TEMPLATE/VCENTER_HOST"], + :user => @one_host["TEMPLATE/VCENTER_USER"], + :password => @one_host["TEMPLATE/VCENTER_PASSWORD"] } - begin - @vim = RbVmomi::VIM.connect(connection) - rescue Exception => e - raise "Error connecting to #{@host}: #{e.message}" - end + initialize_vim(connection) @root = @vim.root @root.childEntity.each {|dc| - ccrs = dc.hostFolder.childEntity.grep(RbVmomi::VIM::ClusterComputeResource) + ccrs = dc.hostFolder.childEntity.grep( + RbVmomi::VIM::ClusterComputeResource) next if ccrs.nil? - @cluster = ccrs.find{ |ccr| - @one_host.name == ccr.name - } + @cluster = ccrs.find{ |ccr| @one_host.name == ccr.name } - if @cluster - @dc = dc - break - end + (@dc = dc; break) if @cluster } if @dc.nil? || @cluster.nil? @@ -108,17 +93,78 @@ class VIClient end end + ############################################################################ + # Initialize a VIConnection based just on the VIM parameters. The OpenNebula + # client is also initilialize + ############################################################################ + def self.new_connection(user_opts) + + conn = allocate + + conn.initialize_one + + conn.initialize_vim(user_opts) + + return conn + end + # The associated resource pool for this connection def resource_pool return @cluster.resourcePool 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) vms = @dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) return vms.find{ |v| v.config.uuid == uuid } end + + # Builds a hash with the DataCenter / ClusterComputeResource hierarchy + # for this VCenter + def hierarchy + + end + + private: + + ############################################################################ + # Initialize an OpenNebula connection with the default ONE_AUTH + ############################################################################ + def initialize_one + begin + @one = ::OpenNebula::Client.new() + 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(opts={}) + opts = { + :insecure => true + }.merge(user_opts) + + @user = opts[:user] + @pass = opts[:password] + @host = opts[:host] + + begin + @vim = RbVmomi::VIM.connect(opts) + rescue Exception => e + raise "Error connecting to #{@host}: #{e.message}" + end + end end ################################################################################ From 33fd6274b084c197491c89ac3ebcd662eda6a131 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 19 Sep 2014 13:14:57 +0200 Subject: [PATCH 12/37] Feature #2911: Add install.sh and oned.conf for vCenter --- install.sh | 29 +++++++++++++++++++++++++++++ share/etc/oned.conf | 24 ++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/install.sh b/install.sh index 40947c503a..c82961d1f3 100755 --- a/install.sh +++ b/install.sh @@ -247,6 +247,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/im/xen3-probes.d \ $VAR_LOCATION/remotes/im/xen4-probes.d \ $VAR_LOCATION/remotes/im/vmware.d \ + $VAR_LOCATION/remotes/im/vcenter.d \ $VAR_LOCATION/remotes/im/ec2.d \ $VAR_LOCATION/remotes/im/sl.d \ $VAR_LOCATION/remotes/im/az.d \ @@ -255,6 +256,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/vmm/xen3 \ $VAR_LOCATION/remotes/vmm/xen4 \ $VAR_LOCATION/remotes/vmm/vmware \ + $VAR_LOCATION/remotes/vmm/vcenter \ $VAR_LOCATION/remotes/vmm/ec2 \ $VAR_LOCATION/remotes/vmm/sl \ $VAR_LOCATION/remotes/vmm/az \ @@ -407,6 +409,7 @@ INSTALL_FILES=( IM_PROBES_XEN4_FILES:$VAR_LOCATION/remotes/im/xen4.d IM_PROBES_XEN4_PROBES_FILES:$VAR_LOCATION/remotes/im/xen4-probes.d IM_PROBES_VMWARE_FILES:$VAR_LOCATION/remotes/im/vmware.d + IM_PROBES_VCENTER_FILES:$VAR_LOCATION/remotes/im/vcenter.d IM_PROBES_EC2_FILES:$VAR_LOCATION/remotes/im/ec2.d IM_PROBES_SL_FILES:$VAR_LOCATION/remotes/im/sl.d IM_PROBES_AZ_FILES:$VAR_LOCATION/remotes/im/az.d @@ -422,6 +425,7 @@ INSTALL_FILES=( VMM_EXEC_XEN3_SCRIPTS:$VAR_LOCATION/remotes/vmm/xen3 VMM_EXEC_XEN4_SCRIPTS:$VAR_LOCATION/remotes/vmm/xen4 VMM_EXEC_VMWARE_SCRIPTS:$VAR_LOCATION/remotes/vmm/vmware + VMM_EXEC_VCENTER_SCRIPTS:$VAR_LOCATION/remotes/vmm/vcenter VMM_EXEC_EC2_SCRIPTS:$VAR_LOCATION/remotes/vmm/ec2 VMM_EXEC_SL_SCRIPTS:$VAR_LOCATION/remotes/vmm/sl VMM_EXEC_AZ_SCRIPTS:$VAR_LOCATION/remotes/vmm/az @@ -759,6 +763,29 @@ VMM_EXEC_VMWARE_SCRIPTS="src/vmm_mad/remotes/vmware/cancel \ src/vmm_mad/remotes/vmware/vmware_driver.rb \ src/vmm_mad/remotes/vmware/vi_driver.rb" +#------------------------------------------------------------------------------- +# VMM Driver vCenter scripts, installed under $REMOTES_LOCATION/vmm/vcenter +#------------------------------------------------------------------------------- + +VMM_EXEC_VMWARE_SCRIPTS="src/vmm_mad/remotes/vcenter/cancel \ + src/vmm_mad/remotes/vcenter/attach_disk \ + src/vmm_mad/remotes/vcenter/detach_disk \ + src/vmm_mad/remotes/vcenter/attach_nic \ + src/vmm_mad/remotes/vcenter/detach_nic \ + src/vmm_mad/remotes/vcenter/snapshot_create \ + src/vmm_mad/remotes/vcenter/snapshot_revert \ + src/vmm_mad/remotes/vcenter/snapshot_delete \ + src/vmm_mad/remotes/vcenter/deploy \ + src/vmm_mad/remotes/vcenter/migrate \ + src/vmm_mad/remotes/vcenter/restore \ + src/vmm_mad/remotes/vcenter/reboot \ + src/vmm_mad/remotes/vcenter/reset \ + src/vmm_mad/remotes/vcenter/save \ + src/vmm_mad/remotes/vcenter/poll \ + src/vmm_mad/remotes/vcenter/checkpoint \ + src/vmm_mad/remotes/vcenter/shutdown \ + src/vmm_mad/remotes/vcenter/vcenter_driver.rb" + #------------------------------------------------------------------------------ # VMM Driver EC2 scripts, to be installed under $REMOTES_LOCATION/vmm/ec2 #------------------------------------------------------------------------------ @@ -870,6 +897,8 @@ IM_PROBES_XEN4_PROBES_FILES="src/im_mad/remotes/xen-probes.d/xen.rb \ IM_PROBES_VMWARE_FILES="src/im_mad/remotes/vmware.d/vmware.rb" +IM_PROBES_VCENTER_FILES="src/im_mad/remotes/vcenter.d/vcenter.rb" + IM_PROBES_EC2_FILES="src/im_mad/remotes/ec2.d/poll" IM_PROBES_SL_FILES="src/im_mad/remotes/sl.d/poll" diff --git a/share/etc/oned.conf b/share/etc/oned.conf index d02300aee5..b3c6cbb6b6 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -310,6 +310,17 @@ IM_MAD = [ # arguments = "-c -t 15 -r 0 vmware" ] #------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +# vCenter Information Driver Manager Configuration +# -r number of retries when monitoring a host +# -t number of threads, i.e. number of hosts monitored at the same time +#------------------------------------------------------------------------------- +#IM_MAD = [ +# name = "vcenter", +# executable = "one_im_sh", +# arguments = "-c -t 15 -r 0 vcenter" ] +#------------------------------------------------------------------------------- + #------------------------------------------------------------------------------- # EC2 Information Driver Manager Configuration # -r number of retries when monitoring a host @@ -431,6 +442,19 @@ VM_MAD = [ # type = "vmware" ] #------------------------------------------------------------------------------- + +#------------------------------------------------------------------------------- +# vCenter Virtualization Driver Manager Configuration +# -r number of retries when monitoring a host +# -t number of threads, i.e. number of hosts monitored at the same time +#------------------------------------------------------------------------------- +#VM_MAD = [ +# name = "vcenter", +# executable = "one_vmm_sh", +# arguments = "-t 15 -r 0 vcenter -s sh", +# type = "xml" ] +#------------------------------------------------------------------------------- + #------------------------------------------------------------------------------- # EC2 Virtualization Driver Manager Configuration # -r number of retries when monitoring a host From 194c7fdfb3eaa388362688d8f314d7af88b49bb1 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 19 Sep 2014 14:22:24 +0200 Subject: [PATCH 13/37] Feature #2911: Minor bugs vCenter driver --- src/im_mad/remotes/vcenter.d/vcenter.rb | 2 +- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/vcenter.rb index 2d71377083..a7b7649632 100644 --- a/src/im_mad/remotes/vcenter.d/vcenter.rb +++ b/src/im_mad/remotes/vcenter.d/vcenter.rb @@ -28,7 +28,7 @@ $: << "../../vmm/vcenter/" require 'vcenter_driver' -host_id = ARGV[0] +host_id = ARGV[4] if !host_id exit -1 diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 222e311f9d..6c9948d46c 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -129,7 +129,7 @@ class VIClient end - private: + private ############################################################################ # Initialize an OpenNebula connection with the default ONE_AUTH @@ -150,7 +150,7 @@ class VIClient # :host => vCenter hostname or IP # :insecure => SSL (optional, defaults to true) ############################################################################ - def initialize_vim(opts={}) + def initialize_vim(user_opts={}) opts = { :insecure => true }.merge(user_opts) From 25a7e0f83b53d2b90738d0b4c0ae4452471df141 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 19 Sep 2014 19:26:02 +0200 Subject: [PATCH 14/37] Feature #2911: Add more vcenter actions --- install.sh | 2 +- src/vmm_mad/remotes/vcenter/attach_disk | 20 +++ src/vmm_mad/remotes/vcenter/attach_nic | 20 +++ src/vmm_mad/remotes/vcenter/cancel | 41 +++++ src/vmm_mad/remotes/vcenter/detach_disk | 20 +++ src/vmm_mad/remotes/vcenter/detach_nic | 20 +++ src/vmm_mad/remotes/vcenter/migrate | 20 +++ src/vmm_mad/remotes/vcenter/poll | 40 +++++ src/vmm_mad/remotes/vcenter/reboot | 41 +++++ src/vmm_mad/remotes/vcenter/reset | 41 +++++ src/vmm_mad/remotes/vcenter/restore | 41 +++++ src/vmm_mad/remotes/vcenter/revert_snapshot | 44 +++++ src/vmm_mad/remotes/vcenter/save | 42 +++++ src/vmm_mad/remotes/vcenter/shutdown | 37 ++++ src/vmm_mad/remotes/vcenter/snapshot_create | 44 +++++ src/vmm_mad/remotes/vcenter/snapshot_delete | 44 +++++ src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 165 +++++++++++++++++- 17 files changed, 679 insertions(+), 3 deletions(-) create mode 100644 src/vmm_mad/remotes/vcenter/attach_disk create mode 100755 src/vmm_mad/remotes/vcenter/attach_nic create mode 100644 src/vmm_mad/remotes/vcenter/cancel create mode 100755 src/vmm_mad/remotes/vcenter/detach_disk create mode 100755 src/vmm_mad/remotes/vcenter/detach_nic create mode 100755 src/vmm_mad/remotes/vcenter/migrate create mode 100644 src/vmm_mad/remotes/vcenter/poll create mode 100644 src/vmm_mad/remotes/vcenter/reboot create mode 100644 src/vmm_mad/remotes/vcenter/reset create mode 100644 src/vmm_mad/remotes/vcenter/restore create mode 100644 src/vmm_mad/remotes/vcenter/revert_snapshot create mode 100644 src/vmm_mad/remotes/vcenter/save create mode 100644 src/vmm_mad/remotes/vcenter/shutdown create mode 100644 src/vmm_mad/remotes/vcenter/snapshot_create create mode 100644 src/vmm_mad/remotes/vcenter/snapshot_delete diff --git a/install.sh b/install.sh index c82961d1f3..07271d407f 100755 --- a/install.sh +++ b/install.sh @@ -767,7 +767,7 @@ VMM_EXEC_VMWARE_SCRIPTS="src/vmm_mad/remotes/vmware/cancel \ # VMM Driver vCenter scripts, installed under $REMOTES_LOCATION/vmm/vcenter #------------------------------------------------------------------------------- -VMM_EXEC_VMWARE_SCRIPTS="src/vmm_mad/remotes/vcenter/cancel \ +VMM_EXEC_VCENTER_SCRIPTS="src/vmm_mad/remotes/vcenter/cancel \ src/vmm_mad/remotes/vcenter/attach_disk \ src/vmm_mad/remotes/vcenter/detach_disk \ src/vmm_mad/remotes/vcenter/attach_nic \ diff --git a/src/vmm_mad/remotes/vcenter/attach_disk b/src/vmm_mad/remotes/vcenter/attach_disk new file mode 100644 index 0000000000..8aeaf8eba5 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/attach_disk @@ -0,0 +1,20 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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 diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic new file mode 100755 index 0000000000..8aeaf8eba5 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -0,0 +1,20 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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 diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel new file mode 100644 index 0000000000..72cf74a372 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -0,0 +1,41 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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' + +deploy_id = ARGV[0] +host = ARGV[1] + +begin + puts VCenterDriver::VCenterVm.cancel(deploy_id, host) + exit 0 +rescue Exception => e + STDERR.puts "Cancel of VM #{deploy_id} on host #{host} failed " + + "due to \"#{e.message}\"" +end diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk new file mode 100755 index 0000000000..8aeaf8eba5 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/detach_disk @@ -0,0 +1,20 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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 diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic new file mode 100755 index 0000000000..8aeaf8eba5 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -0,0 +1,20 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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 diff --git a/src/vmm_mad/remotes/vcenter/migrate b/src/vmm_mad/remotes/vcenter/migrate new file mode 100755 index 0000000000..8aeaf8eba5 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/migrate @@ -0,0 +1,20 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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 diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll new file mode 100644 index 0000000000..4136cee0e6 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/poll @@ -0,0 +1,40 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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' + +deploy_id = ARGV[0] +host = ARGV[1] + +host_id = VCenterDriver::VCenterVm.translate_hostname(host) +vi_client = VCenterDriver::VIClient.new host_id +vm = connection.find_vm_template(deploy_id) + +puts vm.info diff --git a/src/vmm_mad/remotes/vcenter/reboot b/src/vmm_mad/remotes/vcenter/reboot new file mode 100644 index 0000000000..b03df8406c --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/reboot @@ -0,0 +1,41 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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' + +deploy_id = ARGV[0] +host = ARGV[1] + +begin + puts VCenterDriver::VCenterVm.reboot(deploy_id, host) + exit 0 +rescue Exception => e + STDERR.puts "Guest reboot of VM #{deploy_id} on host #{host} failed " + + "due to \"#{e.message}\"" +end diff --git a/src/vmm_mad/remotes/vcenter/reset b/src/vmm_mad/remotes/vcenter/reset new file mode 100644 index 0000000000..8e59a9a5a4 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/reset @@ -0,0 +1,41 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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 'vmware_driver' + +deploy_id = ARGV[0] +host = ARGV[1] + +begin + puts VCenterDriver::VCenterVm.reset(deploy_id, host) + exit 0 +rescue Exception => e + STDERR.puts "Reset of VM #{deploy_id} on host #{host} failed " + + "due to \"#{e.message}\"" +end diff --git a/src/vmm_mad/remotes/vcenter/restore b/src/vmm_mad/remotes/vcenter/restore new file mode 100644 index 0000000000..4623dfb6ca --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/restore @@ -0,0 +1,41 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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' + +host = ARGV[-1] +deploy_id = ARGV[2] + +begin + puts VCenterDriver::VCenterVm.resume(deploy_id, host) + exit 0 +rescue Exception => e + STDERR.puts "Restore of VM #{deploy_id} on host #{host} failed " + + "due to \"#{e.message}\"" +end diff --git a/src/vmm_mad/remotes/vcenter/revert_snapshot b/src/vmm_mad/remotes/vcenter/revert_snapshot new file mode 100644 index 0000000000..5a2ba4c4de --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/revert_snapshot @@ -0,0 +1,44 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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' + +deploy_id = ARGV[0] +snapshot_name = ARGV[1] +host = ARGV[3] + +begin + puts VCenterDriver::VCenterVm.revert_snapshot(deploy_id, + host, + snapshot_name) + exit 0 +rescue Exception => e + STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} could not be " + + "reverted due to \"#{e.message}\"" +end diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save new file mode 100644 index 0000000000..8ffc2adb72 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/save @@ -0,0 +1,42 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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' + +deploy_id = ARGV[0] +file = ARGV[1] +host = ARGV[2] + +begin + puts VCenterDriver::VCenterVm.save(deploy_id, host) + exit 0 +rescue Exception => e + STDERR.puts "Save of VM #{deploy_id} on host #{host} failed " + + "due to \"#{e.message}\"" +end diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown new file mode 100644 index 0000000000..fd986aff83 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -0,0 +1,37 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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' + +deploy_id = ARGV[0] +host = ARGV[1] + +vmware_drv = VMwareDriver.new(host) + +vmware_drv.shutdown(deploy_id) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create new file mode 100644 index 0000000000..2860826b5c --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -0,0 +1,44 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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' + +deploy_id = ARGV[0] +snapshot_name = ARGV[1] +host = ARGV[3] + +begin + puts VCenterDriver::VCenterVm.create_snapshot(deploy_id, + host, + snapshot_name) + exit 0 +rescue Exception => e + STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} failed " + + "due to \"#{e.message}\"" +end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete new file mode 100644 index 0000000000..cf81e3fabe --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -0,0 +1,44 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L # +# # +# 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' + +deploy_id = ARGV[0] +snapshot_name = ARGV[1] +host = ARGV[3] + +begin + puts VCenterDriver::VCenterVm.delete_snapshot(deploy_id, + host, + snapshot_name) + exit 0 +rescue Exception => e + STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} failed " + + "due to \"#{e.message}\"" +end diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 6c9948d46c..c4d6331c35 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -129,6 +129,15 @@ class VIClient 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 + private ############################################################################ @@ -322,8 +331,7 @@ class VCenterVm ############################################################################ # Deploys a VM - # @param host the hostname of the OpenNebula host to deploy the VM - # @xml_test the XML of the + # @xml_text XML repsentation of the VM ############################################################################ def self.deploy(xml_text) @@ -373,6 +381,159 @@ class VCenterVm return rc.config.uuid end + ############################################################################ + # Cancels a VM + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + ############################################################################ + def self.cancel(deploy_id, hostname) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.TerminateVM + 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) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.SuspendVM_Task.wait_for_completion + 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.PowerOnVM_Task.wait_for_completion + end + + ############################################################################ + # Resets a VM + # @param deploy_id vcenter 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) + ############################################################################ + def self.shutdown(deploy_id, hostname) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.ShutdownGuest.wait_for_completion + 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 + 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) + + snapshot = vm.snapshot.rootSnapshotList.find {|s| + s.name == snapshot_name + }.snapshot + + delete_snapshot_hash = { + :_this => snapshot, + :removeChildren => true + } + + vm.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) + + snapshot = vm.snapshot.rootSnapshotList.find {|s| + s.name == snapshot_name + }.snapshot + + revert_snapshot_hash = { + :_this => snapshot + } + + vm.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion + end + ######################################################################## # Initialize the vm monitor information ######################################################################## From c418d3d573251cd76494a82e122b6396824b66ff Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Sun, 21 Sep 2014 00:44:11 +0200 Subject: [PATCH 15/37] feature #2911b: Import tools for vCenter clusters --- src/cli/onevcenter | 147 +++ src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 1131 +++++++++-------- 2 files changed, 738 insertions(+), 540 deletions(-) create mode 100644 src/cli/onevcenter diff --git a/src/cli/onevcenter b/src/cli/onevcenter new file mode 100644 index 0000000000..78f99b0c7f --- /dev/null +++ b/src/cli/onevcenter @@ -0,0 +1,147 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# 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 !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" + REMOTES_LOCATION="/var/lib/one/remotes/" +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" + REMOTES_LOCATION=ONE_LOCATION+"/var/remotes/" +end + +$: << RUBY_LIB_LOCATION +$: << RUBY_LIB_LOCATION+"/cli" +$: << REMOTES_LOCATION+"vmm/vcenter/" + +require 'command_parser' +require 'one_helper/onehost_helper' +require 'one_helper/onecluster_helper' +require 'vcenter_driver' + +cmd=CommandParser::CmdParser.new(ARGV) do + + usage "`onevcenter` [] []" + version OpenNebulaHelper::ONE_VERSION + + helper = OneHostHelper.new + + before_proc do + helper.set_client(options) + end + + ######################################################################## + # Global Options + ######################################################################## + cmd_options=CommandParser::OPTIONS-[CommandParser::VERBOSE] + set :option, cmd_options+OpenNebulaHelper::CLIENT_OPTIONS + + + VCENTER = { + :name => "vcenter", + :large => "--vcenter vCenter" , + :description => "The vCenter hostname", + :format => String + } + + USER = { + :name => "vuser", + :large => "--vuser username" , + :description => "The username to interact with vCenter", + :format => String + } + + PASS = { + :name => "vpass", + :large => "--vpass password", + :description => "The password for the user", + :format => String + } + + ############################################################################ + # Import clusters + ############################################################################ + hosts_desc = <<-EOT.unindent + Import vCenter clusters as OpenNebula hosts + EOT + + command :hosts, hosts_desc, :options=>[ VCENTER, USER, PASS ] do + if options[:vuser].nil? || + options[:vpass].nil? || + options[:vcenter].nil? + STDERR.puts "vCenter connection parameters are mandatory to import"\ + " host:\n"\ + "\t --vcenter vCenter hostname\n"\ + "\t --vuser username to login in vcenter\n"\ + "\t --vpass password for the user" + exit -1 + end + + begin + STDOUT.print "Connecting to vCenter: #{options[:vcenter]}..." + + vc = VCenterDriver::VIClient.new_connection( + :user => options[:vuser], + :password => options[:vpass], + :host => options[:vcenter]) + + STDOUT.puts "done!" + + STDOUT.print "Exploring vCenter resources..." + + rs = vc.hierarchy + + STDOUT.puts "done!" + + 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 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 + + exit 0 + #h = VCenterDriver::VCenterHost.to_one(vc) + end +end diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index c4d6331c35..255e0a676e 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -1,599 +1,650 @@ -# ---------------------------------------------------------------------------- # -# Copyright 2010-2014, C12G Labs S.L # -# # -# 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 2010-2014, C12G Labs S.L # + # # + # 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) + # -------------------------------------------------------------------------# + # 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 + 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' + ENV['LANG'] = 'C' -$: << LIB_LOCATION+'/ruby/vendors/rbvmomi/lib' -$: << LIB_LOCATION+'/ruby' + $: << LIB_LOCATION+'/ruby/vendors/rbvmomi/lib' + $: << LIB_LOCATION+'/ruby' -require 'rbvmomi' -require 'yaml' -require 'opennebula' + require 'rbvmomi' + require 'yaml' + require 'opennebula' -module VCenterDriver + 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 + ################################################################################ + # 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 - ############################################################################ - # Initializr 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) + ############################################################################ + # Initializr 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 + initialize_one - @one_host = ::OpenNebula::Host.new_with_id(hid, @one) - rc = @one_host.info + @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}" + if ::OpenNebula.is_error?(rc) + raise "Error getting host information: #{rc.message}" + end + + connection = { + :host => @one_host["TEMPLATE/VCENTER_HOST"], + :user => @one_host["TEMPLATE/VCENTER_USER"], + :password => @one_host["TEMPLATE/VCENTER_PASSWORD"] + } + + initialize_vim(connection) + + @root.childEntity.each {|dc| + ccrs = dc.hostFolder.childEntity.grep( + RbVmomi::VIM::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 - connection = { - :host => @one_host["TEMPLATE/VCENTER_HOST"], - :user => @one_host["TEMPLATE/VCENTER_USER"], - :password => @one_host["TEMPLATE/VCENTER_PASSWORD"] - } + ######################################################################## + # Initialize a VIConnection based just on the VIM parameters. The + # OpenNebula client is also initilialize + ######################################################################## + def self.new_connection(user_opts) - initialize_vim(connection) + conn = allocate - @root = @vim.root + conn.initialize_one - @root.childEntity.each {|dc| - ccrs = dc.hostFolder.childEntity.grep( - RbVmomi::VIM::ClusterComputeResource) + conn.initialize_vim(user_opts) - next if ccrs.nil? + return conn + end - @cluster = ccrs.find{ |ccr| @one_host.name == ccr.name } + ######################################################################## + # The associated resource pool for this connection + ######################################################################## + def resource_pool + return @cluster.resourcePool + end - (@dc = dc; break) if @cluster - } + ######################################################################## + # 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) + vms = @dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) - if @dc.nil? || @cluster.nil? - raise "Cannot find DataCenter or ClusterComputeResource for host." + return vms.find{ |v| v.config.uuid == uuid } + end + + ######################################################################## + # Builds a hash with the DataCenter / ClusterComputeResource hierarchy + # for this VCenter. + # @return [Hash] in the form + # { dc_name [String] => ClusterComputeResources [Array] } + ######################################################################## + def hierarchy + vc_hosts = {} + + @root.childEntity.each { |dc| + + ccrs = dc.hostFolder.childEntity.grep( + RbVmomi::VIM::ClusterComputeResource) + + vc_hosts[dc.name] = ccrs.collect { |c| c.name } + } + + return vc_hosts + 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 + + ############################################################################ + # Initialize an OpenNebula connection with the default ONE_AUTH + ############################################################################ + def initialize_one + begin + @one = ::OpenNebula::Client.new() + 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 + rescue Exception => e + raise "Error connecting to #{@host}: #{e.message}" + end end end - ############################################################################ - # Initialize a VIConnection based just on the VIM parameters. The OpenNebula - # client is also initilialize - ############################################################################ - def self.new_connection(user_opts) + ################################################################################ + # 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 - conn = allocate + ############################################################################ + # 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 - conn.initialize_one + @resource_pool = client.resource_pool + end - conn.initialize_vim(user_opts) + ######################################################################## + # 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) - return conn - end + rc = one_host.allocate(cluster_name, 'vcenter', 'vcenter', 'dummy', + ::OpenNebula::ClusterPool::NONE_CLUSTER_ID) - # The associated resource pool for this connection - def resource_pool - return @cluster.resourcePool - end + return -1, rc.message if ::OpenNebula.is_error?(rc) - # 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) - vms = @dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) + template = "VCENTER_HOST=\"#{client.host}\"\n"\ + "VCENTER_PASSWORD=\"#{client.pass}\"\n"\ + "VCENTER_USER=\"#{client.user}\"\n" - return vms.find{ |v| v.config.uuid == uuid } - end + rc = one_host.update(template, false) + if ::OpenNebula.is_error?(rc) + error = rc.message - # Builds a hash with the DataCenter / ClusterComputeResource hierarchy - # for this VCenter - def hierarchy + rc = one_host.delete - end + if ::OpenNebula.is_error?(rc) + error << ". Host #{cluster_name} could not be"\ + " deleted: #{rc.message}." + 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) + return -1, error + end - host = host_pool.select {|host_element| host_element.name==hostname } - return host.first.id - end + return 0, one_host.id + end - private + ############################################################################ + # Generate an OpenNebula monitor string for this host. Reference: + # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/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 - ############################################################################ - # Initialize an OpenNebula connection with the default ONE_AUTH - ############################################################################ - def initialize_one - begin - @one = ::OpenNebula::Client.new() - rescue Exception => e - raise "Error initializing OpenNebula client: #{e.message}" + 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 << "PUBLIC_CLOUD=YES\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 + 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 << "TOTALCPU=" << total_cpu.to_s << "," + host_info << "USEDCPU=" << used_cpu.to_s << "," + host_info << "FREECPU=" << free_cpu.to_s << "," + host_info << "TOTALMEMORY=" << total_memory.to_s << "," + host_info << "USEDMEMORY=" << used_memory.to_s << "," + host_info << "FREEMEMORY=" << free_memory.to_s + host_info << "]" + } + + return host_info + end + + def monitor_vms + str_info = "" + @resource_pool.vm.each { |v| + name = v.name + number = -1 + number = name.split('-').last if (name =~ /^one-\d*$/) + + vm = VCenterVm.new(@client, v) + vm.monitor + + str_info << "\nVM = [" + str_info << "ID=#{number}," + str_info << "DEPLOY_ID=\"#{name}\"," + str_info << "POLL=\"#{vm.info}\"]" + } + + return str_info 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) + ################################################################################ + # This class is a high level abstraction of a VI VirtualMachine class with + # OpenNebula semantics. + ################################################################################ + + class VCenterVm + ############################################################################ + # Creates a new VIVm using a RbVmomi::VirtualMachine object + # @param vm_vi [RbVmomi::VirtualMachine] it will be used if not nil + ######################################################################## + def initialize(client, vm_vi ) + @vm = vm_vi + @client = client - @user = opts[:user] - @pass = opts[:password] - @host = opts[:host] - - begin - @vim = RbVmomi::VIM.connect(opts) - rescue Exception => e - raise "Error connecting to #{@host}: #{e.message}" - end - 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_pool = client.resource_pool - end - - ############################################################################ - # Generate an OpenNebula monitor string for this host. Reference: - # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/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 << "PUBLIC_CLOUD=YES\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 - 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 << "TOTALCPU=" << total_cpu.to_s << "," - host_info << "USEDCPU=" << used_cpu.to_s << "," - host_info << "FREECPU=" << free_cpu.to_s << "," - host_info << "TOTALMEMORY=" << total_memory.to_s << "," - host_info << "USEDMEMORY=" << used_memory.to_s << "," - host_info << "FREEMEMORY=" << free_memory.to_s - host_info << "]" - } - - return host_info - end - - def monitor_vms - str_info = "" - @resource_pool.vm.each { |v| - name = v.name - number = -1 - number = name.split('-').last if (name =~ /^one-\d*$/) - - vm = VCenterVm.new(@client, v) - vm.monitor - - str_info << "\nVM = [" - str_info << "ID=#{number}," - str_info << "DEPLOY_ID=\"#{name}\"," - str_info << "POLL=\"#{vm.info}\"]" - } - - return str_info - end -end - -################################################################################ -# This class is a high level abstraction of a VI VirtualMachine class with -# OpenNebula semantics. -################################################################################ - -class VCenterVm - ############################################################################ - # Creates a new VIVm using a RbVmomi::VirtualMachine object - # @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 - - @net_rx = 0 - @net_tx = 0 - end - - ############################################################################ - # Deploys a VM - # @xml_text XML repsentation of the VM - ############################################################################ - def self.deploy(xml_text) - - xml = REXML::Document.new xml_text - - pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") - - raise "Cannot find VCenter element in VM template." if pcs.nil? - - template = pcs.find { |t| - type = t.elements["TYPE"] - !type.nil? && type.text.downcase == "vcenter" - } - - 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 - - hid = xml.root.elements["//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_template(uuid) - - relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( - :diskMoveType => :moveChildMostDiskBacking, - :pool => connection.resource_pool) - - clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec( - :location => relocate_spec, - :powerOn => true, - :template => false) - - rc = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => "one-#{vmid}", - :spec => clone_spec).wait_for_completion - - return rc.config.uuid - end - - ############################################################################ - # Cancels a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - ############################################################################ - def self.cancel(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - vm.TerminateVM - 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) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - vm.SuspendVM_Task.wait_for_completion - 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.PowerOnVM_Task.wait_for_completion - end - - ############################################################################ - # Resets a VM - # @param deploy_id vcenter 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) - ############################################################################ - def self.shutdown(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - vm.ShutdownGuest.wait_for_completion - 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 - 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) - - snapshot = vm.snapshot.rootSnapshotList.find {|s| - s.name == snapshot_name - }.snapshot - - delete_snapshot_hash = { - :_this => snapshot, - :removeChildren => true - } - - vm.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) - - snapshot = vm.snapshot.rootSnapshotList.find {|s| - s.name == snapshot_name - }.snapshot - - revert_snapshot_hash = { - :_this => snapshot - } - - vm.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion - end - - ######################################################################## - # Initialize the vm monitor information - ######################################################################## - def monitor - @summary = @vm.summary - @state = state_to_c(@summary.runtime.powerState) - - if @state != 'a' @used_cpu = 0 @used_memory = 0 @net_rx = 0 @net_tx = 0 - - return end - @used_memory = @summary.quickStats.hostMemoryUsage * 1024 + ############################################################################ + # Deploys a VM + # @xml_text XML repsentation of the VM + ############################################################################ + def self.deploy(xml_text) - host = @vm.runtime.host - cpuMhz = host.summary.hardware.cpuMhz.to_f + xml = REXML::Document.new xml_text - @used_cpu = - ((@summary.quickStats.overallCpuUsage.to_f / cpuMhz) * 100).to_s - @used_cpu = sprintf('%.2f',@used_cpu).to_s + pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") - # Check for negative values - @used_memory = 0 if @used_memory.to_i < 0 - @used_cpu = 0 if @used_cpu.to_i < 0 - end + raise "Cannot find VCenter element in VM template." if pcs.nil? - ######################################################################## - # Generates a OpenNebula IM Driver valid string with the monitor info - ######################################################################## - def info - return 'STATE=d' if @state == 'd' + template = pcs.find { |t| + type = t.elements["TYPE"] + !type.nil? && type.text.downcase == "vcenter" + } - str_info = "" + raise "Cannot find VCenter element in VM template." if template.nil? - str_info << "STATE=" << @state << " " - str_info << "USEDCPU=" << @used_cpu.to_s << " " - str_info << "USEDMEMORY="<< @used_memory.to_s << " " - str_info << "NETRX=" << @net_rx.to_s << " " - str_info << "NETTX=" << @net_tx.to_s - end + uuid = template.elements["VM_TEMPLATE"] -private + raise "Cannot find VM_TEMPLATE in VCenter element." if uuid.nil? - ######################################################################## - # Converts the VI string state to OpenNebula state convention - ######################################################################## - def state_to_c(state) - case state - when 'poweredOn' - 'a' - when 'suspended' - 'p' - else - 'd' + uuid = uuid.text + + vmid = xml.root.elements["/VM/ID"].text + + hid = xml.root.elements["//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_template(uuid) + + relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( + :diskMoveType => :moveChildMostDiskBacking, + :pool => connection.resource_pool) + + clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec( + :location => relocate_spec, + :powerOn => true, + :template => false) + + rc = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => "one-#{vmid}", + :spec => clone_spec).wait_for_completion + + return rc.config.uuid + end + + ############################################################################ + # Cancels a VM + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + ############################################################################ + def self.cancel(deploy_id, hostname) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.TerminateVM + 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) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.SuspendVM_Task.wait_for_completion + 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.PowerOnVM_Task.wait_for_completion + end + + ############################################################################ + # Resets a VM + # @param deploy_id vcenter 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) + ############################################################################ + def self.shutdown(deploy_id, hostname) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.ShutdownGuest.wait_for_completion + 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 + 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) + + snapshot = vm.snapshot.rootSnapshotList.find {|s| + s.name == snapshot_name + }.snapshot + + delete_snapshot_hash = { + :_this => snapshot, + :removeChildren => true + } + + vm.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) + + snapshot = vm.snapshot.rootSnapshotList.find {|s| + s.name == snapshot_name + }.snapshot + + revert_snapshot_hash = { + :_this => snapshot + } + + vm.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion + end + + ######################################################################## + # Initialize the vm monitor information + ######################################################################## + def monitor + @summary = @vm.summary + @state = state_to_c(@summary.runtime.powerState) + + if @state != 'a' + @used_cpu = 0 + @used_memory = 0 + + @net_rx = 0 + @net_tx = 0 + + return + end + + @used_memory = @summary.quickStats.hostMemoryUsage * 1024 + + host = @vm.runtime.host + cpuMhz = 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 + end + + ######################################################################## + # Generates a OpenNebula IM Driver valid string with the monitor info + ######################################################################## + def info + return 'STATE=d' if @state == 'd' + + str_info = "" + + str_info << "STATE=" << @state << " " + str_info << "USEDCPU=" << @used_cpu.to_s << " " + str_info << "USEDMEMORY="<< @used_memory.to_s << " " + str_info << "NETRX=" << @net_rx.to_s << " " + str_info << "NETTX=" << @net_tx.to_s + end + + private + + ######################################################################## + # Converts the VI string state to OpenNebula state convention + ######################################################################## + def state_to_c(state) + case state + when 'poweredOn' + 'a' + when 'suspended' + 'p' + else + 'd' + end end end -end -end + end From 1a2ab7ae309a1de6116fb420ca4c32c8ae77a820 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 22 Sep 2014 12:36:39 +0200 Subject: [PATCH 16/37] feature #2911: Import VM Templates from vCenter --- src/cli/onevcenter | 78 ++++++++++++++++++- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 55 ++++++++++++- 2 files changed, 127 insertions(+), 6 deletions(-) diff --git a/src/cli/onevcenter b/src/cli/onevcenter index 78f99b0c7f..c42313e867 100644 --- a/src/cli/onevcenter +++ b/src/cli/onevcenter @@ -94,20 +94,20 @@ cmd=CommandParser::CmdParser.new(ARGV) do end begin - STDOUT.print "Connecting to vCenter: #{options[:vcenter]}..." + STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." vc = VCenterDriver::VIClient.new_connection( :user => options[:vuser], :password => options[:vpass], :host => options[:vcenter]) - STDOUT.puts "done!" + STDOUT.print "done!\n\n" STDOUT.print "Exploring vCenter resources..." rs = vc.hierarchy - STDOUT.puts "done!" + STDOUT.print "done!\n\n" rs.each {|dc, cluster| STDOUT.print "Do you want to process datacenter #{dc} [y/n]? " @@ -142,6 +142,76 @@ cmd=CommandParser::CmdParser.new(ARGV) do end exit 0 - #h = VCenterDriver::VCenterHost.to_one(vc) + end + + templates_desc = <<-EOT.unindent + Import vCenter VM Templates into OpenNebula + EOT + + command :templates, templates_desc, :options=>[ VCENTER, USER, PASS ] do + if options[:vuser].nil? || + options[:vpass].nil? || + options[:vcenter].nil? + STDERR.puts "vCenter connection parameters are mandatory to import"\ + " VM templates:\n"\ + "\t --vcenter vCenter hostname\n"\ + "\t --vuser username to login in vcenter\n"\ + "\t --vpass password for the user" + exit -1 + end + + begin + STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + + vc = VCenterDriver::VIClient.new_connection( + :user => options[:vuser], + :password => options[:vpass], + :host => options[:vcenter]) + + 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 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' + + 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 + + exit 0 end end diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 255e0a676e..90a842b2dd 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -42,7 +42,6 @@ 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. @@ -128,7 +127,7 @@ # Builds a hash with the DataCenter / ClusterComputeResource hierarchy # for this VCenter. # @return [Hash] in the form - # { dc_name [String] => ClusterComputeResources [Array] } + # {dc_name [String] => ClusterComputeResources Names [Array - String]} ######################################################################## def hierarchy vc_hosts = {} @@ -144,6 +143,39 @@ return vc_hosts end + ######################################################################## + # Builds a hash with the Datacenter / VM Templates for this VCenter + # @return [Hash] in the form + # { dc_name [String] => } + ######################################################################## + def vm_templates + vm_templates = {} + + @root.childEntity.each { |dc| + + vms = dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) + + tmp = vms.select { |v| v.config.template == true } + + one_tmp = [] + + tmp.each { |t| + vi_tmp = VCenterVm.new(self, t) + + one_tmp << { + :name => vi_tmp.vm.name, + :uuid => vi_tmp.vm.config.uuid, + :host => vi_tmp.vm.runtime.host.parent.name, + :one => vi_tmp.to_one + } + } + + vm_templates[dc.name] = one_tmp + } + + return vm_templates + end + def self.translate_hostname(hostname) host_pool = OpenNebula::HostPool.new(::OpenNebula::Client.new()) rc = host_pool.info @@ -365,6 +397,8 @@ ################################################################################ class VCenterVm + attr_reader :vm + ############################################################################ # Creates a new VIVm using a RbVmomi::VirtualMachine object # @param vm_vi [RbVmomi::VirtualMachine] it will be used if not nil @@ -631,6 +665,23 @@ str_info << "NETTX=" << @net_tx.to_s end + ######################################################################## + # Generates an OpenNebula Template for this VCenterVm + # + # + ######################################################################## + def to_one + str = "NAME = \"#{@vm.name}\"\n"\ + "CPU = \"#{@vm.config.hardware.numCPU}\"\n"\ + "vCPU = \"#{@vm.config.hardware.numCPU}\"\n"\ + "MEMORY = \"#{@vm.config.hardware.memoryMB}\"\n"\ + "PUBLIC_CLOUD = [\n"\ + " TYPE =\"vcenter\",\n"\ + " VM_TEMPLATE =\"#{@vm.config.uuid}\"\n"\ + "]\n"\ + "SCHED_REQUIREMENTS=\"NAME=\\\"#{@vm.runtime.host.parent.name}\\\"\"\n" + end + private ######################################################################## From 4d6fac6689dae0e2d98d73c4a1ae08d4f782e35f Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 22 Sep 2014 12:37:35 +0200 Subject: [PATCH 17/37] feature #2911: Install the onevcenter tool --- install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install.sh b/install.sh index 07271d407f..e783622f3b 100755 --- a/install.sh +++ b/install.sh @@ -603,6 +603,7 @@ BIN_FILES="src/nebula/oned \ src/cli/onezone \ src/cli/oneflow \ src/cli/oneflow-template \ + src/cli/onevcenter \ src/onedb/onedb \ src/mad/utils/tty_expect \ share/scripts/one" From 62797c024a194e1779acb979a9d5965d0a353b51 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Mon, 22 Sep 2014 15:26:35 +0200 Subject: [PATCH 18/37] Feature #2911: Add proper cancel and shutdown methods for vCenter --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 1264 +++++++++-------- 1 file changed, 633 insertions(+), 631 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 90a842b2dd..63c3d82196 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -1,701 +1,703 @@ - # ---------------------------------------------------------------------------- # - # Copyright 2010-2014, C12G Labs S.L # - # # - # 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 2010-2014, C12G Labs S.L # +# # +# 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) +# -------------------------------------------------------------------------# +# 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) +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' + +require 'rbvmomi' +require 'yaml' +require 'opennebula' + +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 + + ############################################################################ + # Initializr 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 + + connection = { + :host => @one_host["TEMPLATE/VCENTER_HOST"], + :user => @one_host["TEMPLATE/VCENTER_USER"], + :password => @one_host["TEMPLATE/VCENTER_PASSWORD"] + } + + initialize_vim(connection) + + @root.childEntity.each {|dc| + ccrs = dc.hostFolder.childEntity.grep( + RbVmomi::VIM::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 - ENV['LANG'] = 'C' + ######################################################################## + # Initialize a VIConnection based just on the VIM parameters. The + # OpenNebula client is also initilialize + ######################################################################## + def self.new_connection(user_opts) - $: << LIB_LOCATION+'/ruby/vendors/rbvmomi/lib' - $: << LIB_LOCATION+'/ruby' + conn = allocate - require 'rbvmomi' - require 'yaml' - require 'opennebula' + conn.initialize_one - module VCenterDriver + conn.initialize_vim(user_opts) - ################################################################################ - # 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 + return conn + end - ############################################################################ - # Initializr 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) + ######################################################################## + # The associated resource pool for this connection + ######################################################################## + def resource_pool + return @cluster.resourcePool + end - initialize_one + ######################################################################## + # 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) + vms = @dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) - @one_host = ::OpenNebula::Host.new_with_id(hid, @one) - rc = @one_host.info + return vms.find{ |v| v.config.uuid == uuid } + end - if ::OpenNebula.is_error?(rc) - raise "Error getting host information: #{rc.message}" - 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 + vc_hosts = {} - connection = { - :host => @one_host["TEMPLATE/VCENTER_HOST"], - :user => @one_host["TEMPLATE/VCENTER_USER"], - :password => @one_host["TEMPLATE/VCENTER_PASSWORD"] - } + @root.childEntity.each { |dc| - initialize_vim(connection) + ccrs = dc.hostFolder.childEntity.grep( + RbVmomi::VIM::ClusterComputeResource) - @root.childEntity.each {|dc| - ccrs = dc.hostFolder.childEntity.grep( - RbVmomi::VIM::ClusterComputeResource) + vc_hosts[dc.name] = ccrs.collect { |c| c.name } + } - next if ccrs.nil? + return vc_hosts + end - @cluster = ccrs.find{ |ccr| @one_host.name == ccr.name } + ######################################################################## + # Builds a hash with the Datacenter / VM Templates for this VCenter + # @return [Hash] in the form + # { dc_name [String] => } + ######################################################################## + def vm_templates + vm_templates = {} - (@dc = dc; break) if @cluster - } + @root.childEntity.each { |dc| - if @dc.nil? || @cluster.nil? - raise "Cannot find DataCenter or ClusterComputeResource for host." - end - end + vms = dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) - ######################################################################## - # Initialize a VIConnection based just on the VIM parameters. The - # OpenNebula client is also initilialize - ######################################################################## - def self.new_connection(user_opts) + tmp = vms.select { |v| v.config.template == true } - conn = allocate + one_tmp = [] - conn.initialize_one + tmp.each { |t| + vi_tmp = VCenterVm.new(self, t) - conn.initialize_vim(user_opts) - - return conn - end - - ######################################################################## - # The associated resource pool for this connection - ######################################################################## - def resource_pool - return @cluster.resourcePool - 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) - vms = @dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) - - return vms.find{ |v| v.config.uuid == uuid } - 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 - vc_hosts = {} - - @root.childEntity.each { |dc| - - ccrs = dc.hostFolder.childEntity.grep( - RbVmomi::VIM::ClusterComputeResource) - - vc_hosts[dc.name] = ccrs.collect { |c| c.name } - } - - return vc_hosts - end - - ######################################################################## - # Builds a hash with the Datacenter / VM Templates for this VCenter - # @return [Hash] in the form - # { dc_name [String] => } - ######################################################################## - def vm_templates - vm_templates = {} - - @root.childEntity.each { |dc| - - vms = dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine) - - tmp = vms.select { |v| v.config.template == true } - - one_tmp = [] - - tmp.each { |t| - vi_tmp = VCenterVm.new(self, t) - - one_tmp << { - :name => vi_tmp.vm.name, - :uuid => vi_tmp.vm.config.uuid, - :host => vi_tmp.vm.runtime.host.parent.name, - :one => vi_tmp.to_one - } + one_tmp << { + :name => vi_tmp.vm.name, + :uuid => vi_tmp.vm.config.uuid, + :host => vi_tmp.vm.runtime.host.parent.name, + :one => vi_tmp.to_one } - - vm_templates[dc.name] = one_tmp } - return vm_templates - end + vm_templates[dc.name] = one_tmp + } - 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) + return vm_templates + end - host = host_pool.select {|host_element| host_element.name==hostname } - return host.first.id - 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) - ############################################################################ - # Initialize an OpenNebula connection with the default ONE_AUTH - ############################################################################ - def initialize_one - begin - @one = ::OpenNebula::Client.new() - rescue Exception => e - raise "Error initializing OpenNebula client: #{e.message}" - end - end + host = host_pool.select {|host_element| host_element.name==hostname } + return host.first.id + 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 - rescue Exception => e - raise "Error connecting to #{@host}: #{e.message}" - end + ############################################################################ + # Initialize an OpenNebula connection with the default ONE_AUTH + ############################################################################ + def initialize_one + begin + @one = ::OpenNebula::Client.new() + rescue Exception => e + raise "Error initializing OpenNebula client: #{e.message}" 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 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) - ############################################################################ - # 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 + @user = opts[:user] + @pass = opts[:password] + @host = opts[:host] - @resource_pool = client.resource_pool + begin + @vim = RbVmomi::VIM.connect(opts) + @root = @vim.root + rescue Exception => e + raise "Error connecting to #{@host}: #{e.message}" end + end +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) +################################################################################ +# 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 - rc = one_host.allocate(cluster_name, 'vcenter', 'vcenter', 'dummy', - ::OpenNebula::ClusterPool::NONE_CLUSTER_ID) + ############################################################################ + # 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 - return -1, rc.message if ::OpenNebula.is_error?(rc) + @resource_pool = client.resource_pool + end - template = "VCENTER_HOST=\"#{client.host}\"\n"\ - "VCENTER_PASSWORD=\"#{client.pass}\"\n"\ - "VCENTER_USER=\"#{client.user}\"\n" + ######################################################################## + # 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.update(template, false) + rc = one_host.allocate(cluster_name, 'vcenter', 'vcenter', 'dummy', + ::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 = 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 + error << ". Host #{cluster_name} could not be"\ + " deleted: #{rc.message}." end - return 0, one_host.id + return -1, error end - ############################################################################ - # Generate an OpenNebula monitor string for this host. Reference: - # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/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 << "PUBLIC_CLOUD=YES\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 - 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 << "TOTALCPU=" << total_cpu.to_s << "," - host_info << "USEDCPU=" << used_cpu.to_s << "," - host_info << "FREECPU=" << free_cpu.to_s << "," - host_info << "TOTALMEMORY=" << total_memory.to_s << "," - host_info << "USEDMEMORY=" << used_memory.to_s << "," - host_info << "FREEMEMORY=" << free_memory.to_s - host_info << "]" - } - - return host_info - end - - def monitor_vms - str_info = "" - @resource_pool.vm.each { |v| - name = v.name - number = -1 - number = name.split('-').last if (name =~ /^one-\d*$/) - - vm = VCenterVm.new(@client, v) - vm.monitor - - str_info << "\nVM = [" - str_info << "ID=#{number}," - str_info << "DEPLOY_ID=\"#{name}\"," - str_info << "POLL=\"#{vm.info}\"]" - } - - return str_info - end + return 0, one_host.id end - ################################################################################ - # This class is a high level abstraction of a VI VirtualMachine class with - # OpenNebula semantics. - ################################################################################ + ############################################################################ + # Generate an OpenNebula monitor string for this host. Reference: + # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/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 - class VCenterVm - attr_reader :vm + mhz_core = summary.totalCpu.to_f / summary.numCpuCores.to_f + eff_core = summary.effectiveCpu.to_f / mhz_core - ############################################################################ - # Creates a new VIVm using a RbVmomi::VirtualMachine object - # @param vm_vi [RbVmomi::VirtualMachine] it will be used if not nil - ######################################################################## - def initialize(client, vm_vi ) - @vm = vm_vi - @client = client + 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 << "PUBLIC_CLOUD=YES\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 + 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 << "TOTALCPU=" << total_cpu.to_s << "," + host_info << "USEDCPU=" << used_cpu.to_s << "," + host_info << "FREECPU=" << free_cpu.to_s << "," + host_info << "TOTALMEMORY=" << total_memory.to_s << "," + host_info << "USEDMEMORY=" << used_memory.to_s << "," + host_info << "FREEMEMORY=" << free_memory.to_s + host_info << "]" + } + + return host_info + end + + def monitor_vms + str_info = "" + @resource_pool.vm.each { |v| + name = v.name + number = -1 + number = name.split('-').last if (name =~ /^one-\d*$/) + + vm = VCenterVm.new(@client, v) + vm.monitor + + str_info << "\nVM = [" + str_info << "ID=#{number}," + str_info << "DEPLOY_ID=\"#{name}\"," + str_info << "POLL=\"#{vm.info}\"]" + } + + return str_info + end +end + +################################################################################ +# This class is a high level abstraction of a VI VirtualMachine class with +# OpenNebula semantics. +################################################################################ + +class VCenterVm + attr_reader :vm + + ############################################################################ + # Creates a new VIVm using a RbVmomi::VirtualMachine object + # @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 + + @net_rx = 0 + @net_tx = 0 + end + + ############################################################################ + # Deploys a VM + # @xml_text XML repsentation of the VM + ############################################################################ + def self.deploy(xml_text) + + xml = REXML::Document.new xml_text + + pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") + + raise "Cannot find VCenter element in VM template." if pcs.nil? + + template = pcs.find { |t| + type = t.elements["TYPE"] + !type.nil? && type.text.downcase == "vcenter" + } + + 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 + + hid = xml.root.elements["//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_template(uuid) + + relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( + :diskMoveType => :moveChildMostDiskBacking, + :pool => connection.resource_pool) + + clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec( + :location => relocate_spec, + :powerOn => true, + :template => false) + + rc = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => "one-#{vmid}", + :spec => clone_spec).wait_for_completion + + return rc.config.uuid + end + + ############################################################################ + # Cancels a VM + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + ############################################################################ + def self.cancel(deploy_id, hostname) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.PowerOffVM_Task.wait_for_completion + vm.UnregisterVM.wait_for_completion + 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) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.SuspendVM_Task.wait_for_completion + 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.PowerOnVM_Task.wait_for_completion + end + + ############################################################################ + # Resets a VM + # @param deploy_id vcenter 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) + ############################################################################ + def self.shutdown(deploy_id, hostname) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.ShutdownGuest.wait_for_completion + vm.UnregisterVM.wait_for_completion + 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 + 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) + + snapshot = vm.snapshot.rootSnapshotList.find {|s| + s.name == snapshot_name + }.snapshot + + delete_snapshot_hash = { + :_this => snapshot, + :removeChildren => true + } + + vm.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) + + snapshot = vm.snapshot.rootSnapshotList.find {|s| + s.name == snapshot_name + }.snapshot + + revert_snapshot_hash = { + :_this => snapshot + } + + vm.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion + end + + ######################################################################## + # Initialize the vm monitor information + ######################################################################## + def monitor + @summary = @vm.summary + @state = state_to_c(@summary.runtime.powerState) + + if @state != 'a' @used_cpu = 0 @used_memory = 0 @net_rx = 0 @net_tx = 0 + + return end - ############################################################################ - # Deploys a VM - # @xml_text XML repsentation of the VM - ############################################################################ - def self.deploy(xml_text) + @used_memory = @summary.quickStats.hostMemoryUsage * 1024 - xml = REXML::Document.new xml_text + host = @vm.runtime.host + cpuMhz = host.summary.hardware.cpuMhz.to_f - pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") + @used_cpu = + ((@summary.quickStats.overallCpuUsage.to_f / cpuMhz) * 100).to_s + @used_cpu = sprintf('%.2f',@used_cpu).to_s - raise "Cannot find VCenter element in VM template." if pcs.nil? + # Check for negative values + @used_memory = 0 if @used_memory.to_i < 0 + @used_cpu = 0 if @used_cpu.to_i < 0 + end - template = pcs.find { |t| - type = t.elements["TYPE"] - !type.nil? && type.text.downcase == "vcenter" - } + ######################################################################## + # Generates a OpenNebula IM Driver valid string with the monitor info + ######################################################################## + def info + return 'STATE=d' if @state == 'd' - raise "Cannot find VCenter element in VM template." if template.nil? + str_info = "" - uuid = template.elements["VM_TEMPLATE"] + str_info << "STATE=" << @state << " " + str_info << "USEDCPU=" << @used_cpu.to_s << " " + str_info << "USEDMEMORY="<< @used_memory.to_s << " " + str_info << "NETRX=" << @net_rx.to_s << " " + str_info << "NETTX=" << @net_tx.to_s + end - raise "Cannot find VM_TEMPLATE in VCenter element." if uuid.nil? + ######################################################################## + # Generates an OpenNebula Template for this VCenterVm + # + # + ######################################################################## + def to_one + str = "NAME = \"#{@vm.name}\"\n"\ + "CPU = \"#{@vm.config.hardware.numCPU}\"\n"\ + "vCPU = \"#{@vm.config.hardware.numCPU}\"\n"\ + "MEMORY = \"#{@vm.config.hardware.memoryMB}\"\n"\ + "PUBLIC_CLOUD = [\n"\ + " TYPE =\"vcenter\",\n"\ + " VM_TEMPLATE =\"#{@vm.config.uuid}\"\n"\ + "]\n"\ + "SCHED_REQUIREMENTS=\"NAME=\\\"#{@vm.runtime.host.parent.name}\\\"\"\n" + end - uuid = uuid.text +private - vmid = xml.root.elements["/VM/ID"].text - - hid = xml.root.elements["//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_template(uuid) - - relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( - :diskMoveType => :moveChildMostDiskBacking, - :pool => connection.resource_pool) - - clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec( - :location => relocate_spec, - :powerOn => true, - :template => false) - - rc = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => "one-#{vmid}", - :spec => clone_spec).wait_for_completion - - return rc.config.uuid - end - - ############################################################################ - # Cancels a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - ############################################################################ - def self.cancel(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - vm.TerminateVM - 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) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - vm.SuspendVM_Task.wait_for_completion - 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.PowerOnVM_Task.wait_for_completion - end - - ############################################################################ - # Resets a VM - # @param deploy_id vcenter 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) - ############################################################################ - def self.shutdown(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - vm.ShutdownGuest.wait_for_completion - 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 - 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) - - snapshot = vm.snapshot.rootSnapshotList.find {|s| - s.name == snapshot_name - }.snapshot - - delete_snapshot_hash = { - :_this => snapshot, - :removeChildren => true - } - - vm.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) - - snapshot = vm.snapshot.rootSnapshotList.find {|s| - s.name == snapshot_name - }.snapshot - - revert_snapshot_hash = { - :_this => snapshot - } - - vm.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion - end - - ######################################################################## - # Initialize the vm monitor information - ######################################################################## - def monitor - @summary = @vm.summary - @state = state_to_c(@summary.runtime.powerState) - - if @state != 'a' - @used_cpu = 0 - @used_memory = 0 - - @net_rx = 0 - @net_tx = 0 - - return - end - - @used_memory = @summary.quickStats.hostMemoryUsage * 1024 - - host = @vm.runtime.host - cpuMhz = 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 - end - - ######################################################################## - # Generates a OpenNebula IM Driver valid string with the monitor info - ######################################################################## - def info - return 'STATE=d' if @state == 'd' - - str_info = "" - - str_info << "STATE=" << @state << " " - str_info << "USEDCPU=" << @used_cpu.to_s << " " - str_info << "USEDMEMORY="<< @used_memory.to_s << " " - str_info << "NETRX=" << @net_rx.to_s << " " - str_info << "NETTX=" << @net_tx.to_s - end - - ######################################################################## - # Generates an OpenNebula Template for this VCenterVm - # - # - ######################################################################## - def to_one - str = "NAME = \"#{@vm.name}\"\n"\ - "CPU = \"#{@vm.config.hardware.numCPU}\"\n"\ - "vCPU = \"#{@vm.config.hardware.numCPU}\"\n"\ - "MEMORY = \"#{@vm.config.hardware.memoryMB}\"\n"\ - "PUBLIC_CLOUD = [\n"\ - " TYPE =\"vcenter\",\n"\ - " VM_TEMPLATE =\"#{@vm.config.uuid}\"\n"\ - "]\n"\ - "SCHED_REQUIREMENTS=\"NAME=\\\"#{@vm.runtime.host.parent.name}\\\"\"\n" - end - - private - - ######################################################################## - # Converts the VI string state to OpenNebula state convention - ######################################################################## - def state_to_c(state) - case state - when 'poweredOn' - 'a' - when 'suspended' - 'p' - else - 'd' - end + ######################################################################## + # Converts the VI string state to OpenNebula state convention + ######################################################################## + def state_to_c(state) + case state + when 'poweredOn' + 'a' + when 'suspended' + 'p' + else + 'd' end end - end +end +end \ No newline at end of file From 745bcb73ae74317017bce4977ed6ed96f98aa052 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Tue, 23 Sep 2014 16:35:50 +0200 Subject: [PATCH 19/37] feature #2911: Add VNC support for vCenter --- src/sunstone/OpenNebulaVNC.rb | 10 ++++++--- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 22 +++++++++++++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/sunstone/OpenNebulaVNC.rb b/src/sunstone/OpenNebulaVNC.rb index a86969a2c3..c6c76768fa 100644 --- a/src/sunstone/OpenNebulaVNC.rb +++ b/src/sunstone/OpenNebulaVNC.rb @@ -172,9 +172,13 @@ class OpenNebulaVNC end # Proxy data - host = vm_resource['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME'] - vnc_port = vm_resource['TEMPLATE/GRAPHICS/PORT'] - vnc_pw = vm_resource['TEMPLATE/GRAPHICS/PASSWD'] + host = vm_resource['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME'] + vnc_port = vm_resource['TEMPLATE/GRAPHICS/PORT'] + vnc_pw = vm_resource['TEMPLATE/GRAPHICS/PASSWD'] + + if vm_resource['TEMPLATE/ESX_HOST'] # It is behind a vCenter + host = vm_resource['TEMPLATE/ESX_HOST'] + end # Generate token random_str: host:port random_str = rand(36**20).to_s(36) #random string a-z0-9 length 20 diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 63c3d82196..2252f4d926 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -463,7 +463,18 @@ class VCenterVm :name => "one-#{vmid}", :spec => clone_spec).wait_for_completion - return rc.config.uuid + vm_uuid = rc.config.uuid + + vnc_port = xml.root.elements["/VM/TEMPLATE/GRAPHICS/PORT"] + + if vnc_port + spec = RbVmomi::VIM.VirtualMachineConfigSpec(:extraConfig => + [{:key=>"remotedisplay.vnc.enabled", :value=>"TRUE"}, + {:key=>"remotedisplay.vnc.port", :value=>vnc_port.text}]) + rc.ReconfigVM_Task(:spec => spec).wait_for_completion + end + + return vm_uuid end ############################################################################ @@ -478,7 +489,7 @@ class VCenterVm vm = connection.find_vm_template(deploy_id) vm.PowerOffVM_Task.wait_for_completion - vm.UnregisterVM.wait_for_completion + vm.Destroy_Task.wait_for_completion end ############################################################################ @@ -520,7 +531,7 @@ class VCenterVm vm = connection.find_vm_template(deploy_id) - vm.PowerOnVM_Task.wait_for_completion + vm.RebootGuest.wait_for_completion end ############################################################################ @@ -650,6 +661,8 @@ class VCenterVm # 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 end ######################################################################## @@ -664,7 +677,8 @@ class VCenterVm str_info << "USEDCPU=" << @used_cpu.to_s << " " str_info << "USEDMEMORY="<< @used_memory.to_s << " " str_info << "NETRX=" << @net_rx.to_s << " " - str_info << "NETTX=" << @net_tx.to_s + str_info << "NETTX=" << @net_tx.to_s << " " + str_info << "ESX_HOST=" << @esx_host.to_s end ######################################################################## From e832d7fd7a6c729f887392e2196b7661491857e6 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Tue, 23 Sep 2014 17:03:51 +0200 Subject: [PATCH 20/37] feature #2911: Fix polling for vCenter VMs --- src/vmm_mad/remotes/vcenter/poll | 7 +++++-- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll index 4136cee0e6..7de142fe69 100644 --- a/src/vmm_mad/remotes/vcenter/poll +++ b/src/vmm_mad/remotes/vcenter/poll @@ -33,8 +33,11 @@ require 'vcenter_driver' deploy_id = ARGV[0] host = ARGV[1] -host_id = VCenterDriver::VCenterVm.translate_hostname(host) +host_id = VCenterDriver::VIClient.translate_hostname(host) vi_client = VCenterDriver::VIClient.new host_id -vm = connection.find_vm_template(deploy_id) +vm = vi_client.find_vm_template(deploy_id) +vm = VCenterDriver::VCenterVm.new(vi_client, vm) + +vm.monitor puts vm.info diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 2252f4d926..6d5edfe6f2 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -401,6 +401,7 @@ class VCenterVm ############################################################################ # 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 ) From b6560a5ed6c6030155f389b31d7a6a39cfdc569d Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Wed, 24 Sep 2014 17:16:38 +0200 Subject: [PATCH 21/37] feature #2911: Add correct actions for vCenter, solve many bugs --- src/oca/ruby/opennebula/virtual_machine.rb | 11 +- src/vmm_mad/exec/one_vmm_sh | 2 +- src/vmm_mad/remotes/vcenter/cancel | 10 +- src/vmm_mad/remotes/vcenter/deploy | 18 +- src/vmm_mad/remotes/vcenter/reboot | 4 +- src/vmm_mad/remotes/vcenter/reset | 6 +- src/vmm_mad/remotes/vcenter/restore | 4 +- src/vmm_mad/remotes/vcenter/revert_snapshot | 8 +- src/vmm_mad/remotes/vcenter/save | 11 +- src/vmm_mad/remotes/vcenter/shutdown | 15 +- src/vmm_mad/remotes/vcenter/snapshot_create | 4 +- src/vmm_mad/remotes/vcenter/snapshot_delete | 8 +- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 198 +++++++++++------- 13 files changed, 196 insertions(+), 103 deletions(-) diff --git a/src/oca/ruby/opennebula/virtual_machine.rb b/src/oca/ruby/opennebula/virtual_machine.rb index 87bbd37a97..3103662acf 100644 --- a/src/oca/ruby/opennebula/virtual_machine.rb +++ b/src/oca/ruby/opennebula/virtual_machine.rb @@ -224,7 +224,11 @@ module OpenNebula def deploy(host_id, enforce=false, ds_id=-1) enforce ||= false ds_id ||= -1 - return call(VM_METHODS[:deploy], @pe_id, host_id.to_i, enforce, ds_id.to_i) + return call(VM_METHODS[:deploy], + @pe_id, + host_id.to_i, + enforce, + ds_id.to_i) end # Shutdowns an already deployed VM @@ -587,6 +591,11 @@ module OpenNebula self['GID'].to_i end + # Returns the deploy_id of the VirtualMachine (numeric value) + def deploy_id + self['DEPLOY_ID'] + end + private def action(name) return Error.new('ID not defined') if !@pe_id diff --git a/src/vmm_mad/exec/one_vmm_sh b/src/vmm_mad/exec/one_vmm_sh index f87e3dc19f..fcdfebed68 100755 --- a/src/vmm_mad/exec/one_vmm_sh +++ b/src/vmm_mad/exec/one_vmm_sh @@ -25,6 +25,6 @@ fi LOCAL_ACTIONS="deploy,shutdown,reboot,cancel,save,restore,migrate,poll,pre" LOCAL_ACTIONS="${LOCAL_ACTIONS},post,clean" LOCAL_ACTIONS="${LOCAL_ACTIONS},snapshotcreate,snapshotrevert,snapshotdelete" -LOCAL_ACTIONS="${LOCAL_ACTIONS},attach_nic,detach_nic" +LOCAL_ACTIONS="${LOCAL_ACTIONS},attach_nic,detach_nic,reset" exec $MAD_LOCATION/one_vmm_exec -l $LOCAL_ACTIONS $* diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index 72cf74a372..d41f78ef26 100644 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -31,11 +31,17 @@ require 'vcenter_driver' deploy_id = ARGV[0] host = ARGV[1] +vm_id = ARGV[-2] + +vm = OpenNebula::VirtualMachine.new_with_id(vm_id, OpenNebula::Client.new) +vm.info + +lcm_state = vm.lcm_state_str begin - puts VCenterDriver::VCenterVm.cancel(deploy_id, host) - exit 0 + puts VCenterDriver::VCenterVm.cancel(deploy_id, host, lcm_state) rescue Exception => e STDERR.puts "Cancel of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index 5282118339..c0c3834491 100644 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -28,16 +28,26 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver' +require 'opennebula' dfile = ARGV[0] host = ARGV[1] -id = ARGV[2] +vm_id = ARGV[2] + +vm = OpenNebula::VirtualMachine.new_with_id(vm_id, OpenNebula::Client.new) +vm.info + +lcm_state = vm.lcm_state_str +deploy_id = vm.deploy_id begin - puts VCenterDriver::VCenterVm.deploy File.read(dfile) - exit 0 + puts VCenterDriver::VCenterVm.deploy(File.read(dfile), + lcm_state, + deploy_id, + host) rescue Exception => e - STDERR.puts "Deploy of VM #{id} on host #{host} with #{dfile} failed " + + STDERR.puts "Deploy of VM #{vm_id} on host #{host} with #{dfile} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/reboot b/src/vmm_mad/remotes/vcenter/reboot index b03df8406c..7b6d79ad81 100644 --- a/src/vmm_mad/remotes/vcenter/reboot +++ b/src/vmm_mad/remotes/vcenter/reboot @@ -33,9 +33,9 @@ deploy_id = ARGV[0] host = ARGV[1] begin - puts VCenterDriver::VCenterVm.reboot(deploy_id, host) - exit 0 + VCenterDriver::VCenterVm.reboot(deploy_id, host) rescue Exception => e STDERR.puts "Guest reboot of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/reset b/src/vmm_mad/remotes/vcenter/reset index 8e59a9a5a4..0cc9ba4376 100644 --- a/src/vmm_mad/remotes/vcenter/reset +++ b/src/vmm_mad/remotes/vcenter/reset @@ -27,15 +27,15 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vmware_driver' +require 'vcenter_driver' deploy_id = ARGV[0] host = ARGV[1] begin - puts VCenterDriver::VCenterVm.reset(deploy_id, host) - exit 0 + VCenterDriver::VCenterVm.reset(deploy_id, host) rescue Exception => e STDERR.puts "Reset of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/restore b/src/vmm_mad/remotes/vcenter/restore index 4623dfb6ca..fa0191ffe4 100644 --- a/src/vmm_mad/remotes/vcenter/restore +++ b/src/vmm_mad/remotes/vcenter/restore @@ -33,9 +33,9 @@ host = ARGV[-1] deploy_id = ARGV[2] begin - puts VCenterDriver::VCenterVm.resume(deploy_id, host) - exit 0 + VCenterDriver::VCenterVm.resume(deploy_id, host) rescue Exception => e STDERR.puts "Restore of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/revert_snapshot b/src/vmm_mad/remotes/vcenter/revert_snapshot index 5a2ba4c4de..fa96fc4e6e 100644 --- a/src/vmm_mad/remotes/vcenter/revert_snapshot +++ b/src/vmm_mad/remotes/vcenter/revert_snapshot @@ -34,11 +34,11 @@ snapshot_name = ARGV[1] host = ARGV[3] begin - puts VCenterDriver::VCenterVm.revert_snapshot(deploy_id, - host, - snapshot_name) - exit 0 + VCenterDriver::VCenterVm.revert_snapshot(deploy_id, + host, + 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 end diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save index 8ffc2adb72..251c5b2b6a 100644 --- a/src/vmm_mad/remotes/vcenter/save +++ b/src/vmm_mad/remotes/vcenter/save @@ -28,15 +28,22 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver' +require 'opennebula' deploy_id = ARGV[0] file = ARGV[1] host = ARGV[2] +vm_id = ARGV[-2] + +vm = OpenNebula::VirtualMachine.new_with_id(vm_id, OpenNebula::Client.new) +vm.info + +lcm_state = vm.lcm_state_str begin - puts VCenterDriver::VCenterVm.save(deploy_id, host) - exit 0 + 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}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index fd986aff83..565bcd7d3c 100644 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -28,10 +28,21 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver' +require 'opennebula' deploy_id = ARGV[0] host = ARGV[1] +vm_id = ARGV[-2] -vmware_drv = VMwareDriver.new(host) +vm = OpenNebula::VirtualMachine.new_with_id(vm_id, OpenNebula::Client.new) +vm.info -vmware_drv.shutdown(deploy_id) +lcm_state = vm.lcm_state_str + +begin + VCenterDriver::VCenterVm.shutdown(deploy_id, host, lcm_state) +rescue Exception => e + STDERR.puts "Shutdown of VM #{deploy_id} on host #{host} failed " + + "due to \"#{e.message}\"" + exit -1 +end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index 2860826b5c..cc89040dc0 100644 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -34,11 +34,11 @@ snapshot_name = ARGV[1] host = ARGV[3] begin - puts VCenterDriver::VCenterVm.create_snapshot(deploy_id, + VCenterDriver::VCenterVm.create_snapshot(deploy_id, host, snapshot_name) - exit 0 rescue Exception => e STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} 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 cf81e3fabe..68e45639bb 100644 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -34,11 +34,11 @@ snapshot_name = ARGV[1] host = ARGV[3] begin - puts VCenterDriver::VCenterVm.delete_snapshot(deploy_id, - host, - snapshot_name) - exit 0 + VCenterDriver::VCenterVm.delete_snapshot(deploy_id, + host, + snapshot_name) rescue Exception => e STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 6d5edfe6f2..8f4c0a373b 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -419,63 +419,16 @@ class VCenterVm # Deploys a VM # @xml_text XML repsentation of the VM ############################################################################ - def self.deploy(xml_text) - - xml = REXML::Document.new xml_text - - pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") - - raise "Cannot find VCenter element in VM template." if pcs.nil? - - template = pcs.find { |t| - type = t.elements["TYPE"] - !type.nil? && type.text.downcase == "vcenter" - } - - 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 - - hid = xml.root.elements["//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_template(uuid) - - relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( - :diskMoveType => :moveChildMostDiskBacking, - :pool => connection.resource_pool) - - clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec( - :location => relocate_spec, - :powerOn => true, - :template => false) - - rc = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => "one-#{vmid}", - :spec => clone_spec).wait_for_completion - - vm_uuid = rc.config.uuid - - vnc_port = xml.root.elements["/VM/TEMPLATE/GRAPHICS/PORT"] - - if vnc_port - spec = RbVmomi::VIM.VirtualMachineConfigSpec(:extraConfig => - [{:key=>"remotedisplay.vnc.enabled", :value=>"TRUE"}, - {:key=>"remotedisplay.vnc.port", :value=>vnc_port.text}]) - rc.ReconfigVM_Task(:spec => spec).wait_for_completion + def self.deploy(xml_text, lcm_state, deploy_id, hostname) + if lcm_state == "BOOT" + return clone_vm(xml_text) + else + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + vm = connection.find_vm_template(deploy_id) + vm.PowerOnVM_Task.wait_for_completion + return vm.config.uuid end - - return vm_uuid end ############################################################################ @@ -483,14 +436,21 @@ class VCenterVm # @param deploy_id vcenter identifier of the VM # @param hostname name of the host (equals the vCenter cluster) ############################################################################ - def self.cancel(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) + def self.cancel(deploy_id, hostname, lcm_state) + case lcm_state + when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" + shutdown(deploy_id, hostname, lcm_state) + when "CANCEL" + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + vm = connection.find_vm_template(deploy_id) - vm = connection.find_vm_template(deploy_id) - - vm.PowerOffVM_Task.wait_for_completion - vm.Destroy_Task.wait_for_completion + begin + vm.PowerOffVM_Task.wait_for_completion + rescue + end + vm.Destroy_Task.wait_for_completion + end end ############################################################################ @@ -498,13 +458,17 @@ class VCenterVm # @param deploy_id vcenter identifier of the VM # @param hostname name of the host (equals the vCenter cluster) ############################################################################ - def self.save(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) + 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 = connection.find_vm_template(deploy_id) - - vm.SuspendVM_Task.wait_for_completion + vm.SuspendVM_Task.wait_for_completion + end end ############################################################################ @@ -515,7 +479,6 @@ class VCenterVm 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 @@ -554,14 +517,27 @@ class VCenterVm # @param deploy_id vcenter identifier of the VM # @param hostname name of the host (equals the vCenter cluster) ############################################################################ - def self.shutdown(deploy_id, hostname) + def self.shutdown(deploy_id, hostname, lcm_state) hid = VIClient::translate_hostname(hostname) connection = VIClient.new(hid) vm = connection.find_vm_template(deploy_id) - vm.ShutdownGuest.wait_for_completion - vm.UnregisterVM.wait_for_completion + case lcm_state + when "SHUTDOWN" + begin + vm.ShutdownGuest.wait_for_completion + rescue + end + vm.PowerOffVM_Task.wait_for_completion + vm.Destroy_Task.wait_for_completion + when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" + begin + vm.ShutdownGuest.wait_for_completion + rescue + end + vm.PowerOffVM_Task.wait_for_completion + end end ############################################################################ @@ -696,7 +672,11 @@ class VCenterVm " TYPE =\"vcenter\",\n"\ " VM_TEMPLATE =\"#{@vm.config.uuid}\"\n"\ "]\n"\ - "SCHED_REQUIREMENTS=\"NAME=\\\"#{@vm.runtime.host.parent.name}\\\"\"\n" + "GRAPHICS = [\n"\ + " TYPE =\"vnc\",\n"\ + " LISTEN =\"0.0.0.0\"\n"\ + "]\n"\ + "SCHED_REQUIREMENTS=\"NAME=\\\"#{@vm.runtime.host.parent.name}\\\"\"\n" end private @@ -714,5 +694,75 @@ private 'd' end end + + ######################################################################## + # Clone a vCenter VM Template and leaves it powered on + ######################################################################## + def self.clone_vm(xml_text) + + xml = REXML::Document.new xml_text + + pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") + + raise "Cannot find VCenter element in VM template." if pcs.nil? + + template = pcs.find { |t| + type = t.elements["TYPE"] + !type.nil? && type.text.downcase == "vcenter" + } + + 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 + + hid = xml.root.elements["//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_template(uuid) + + relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( + :diskMoveType => :moveChildMostDiskBacking, + :pool => connection.resource_pool) + + clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec( + :location => relocate_spec, + :powerOn => true, + :template => false) + + rc = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => "one-#{vmid}", + :spec => clone_spec).wait_for_completion + + vm_uuid = rc.config.uuid + + vnc_port = xml.root.elements["/VM/TEMPLATE/GRAPHICS/PORT"] + vnc_listen = xml.root.elements["/VM/TEMPLATE/GRAPHICS/LISTEN"] + + if !vnc_listen + vnc_listen = "0.0.0.0" + else + vnc_listen = vnc_listen.text + end + + if vnc_port + spec = RbVmomi::VIM.VirtualMachineConfigSpec(:extraConfig => + [{:key=>"remotedisplay.vnc.enabled", :value=>"TRUE"}, + {:key=>"remotedisplay.vnc.port", :value=>vnc_port.text}, + {:key=>"remotedisplay.vnc.ip", :value=>vnc_listen}]) + rc.ReconfigVM_Task(:spec => spec).wait_for_completion + end + + return vm_uuid + end end end \ No newline at end of file From 85f1d57f724b2d8d3fae085362855740a2e8a6cb Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Thu, 25 Sep 2014 15:09:49 +0200 Subject: [PATCH 22/37] feature #2911: Fix wrong script name --- src/vmm_mad/remotes/vcenter/{revert_snapshot => snapshot_revert} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/vmm_mad/remotes/vcenter/{revert_snapshot => snapshot_revert} (100%) diff --git a/src/vmm_mad/remotes/vcenter/revert_snapshot b/src/vmm_mad/remotes/vcenter/snapshot_revert similarity index 100% rename from src/vmm_mad/remotes/vcenter/revert_snapshot rename to src/vmm_mad/remotes/vcenter/snapshot_revert From f559e1e31a5ac9bda975ef0f5492522c8a69097c Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Thu, 25 Sep 2014 15:59:54 +0200 Subject: [PATCH 23/37] feature #2911: Add extra monitoring information to vCenter VMs --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 8f4c0a373b..6b3c57503e 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -639,7 +639,14 @@ class VCenterVm @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 + @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 + + end ######################################################################## @@ -650,12 +657,17 @@ class VCenterVm str_info = "" - str_info << "STATE=" << @state << " " - str_info << "USEDCPU=" << @used_cpu.to_s << " " - str_info << "USEDMEMORY="<< @used_memory.to_s << " " - str_info << "NETRX=" << @net_rx.to_s << " " - str_info << "NETTX=" << @net_tx.to_s << " " - str_info << "ESX_HOST=" << @esx_host.to_s + str_info << "GUEST_IP=" << @guest_ip.to_s << " " if @guest_ip + str_info << "STATE=" << @state << " " + str_info << "USEDCPU=" << @used_cpu.to_s << " " + str_info << "USEDMEMORY=" << @used_memory.to_s << " " + str_info << "NETRX=" << @net_rx.to_s << " " + str_info << "NETTX=" << @net_tx.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 << " " end ######################################################################## From 956b691878c4bfcd8d8be1c717645ad61ffeb633 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Thu, 25 Sep 2014 12:22:51 +0200 Subject: [PATCH 24/37] feature #2911: Add vCenter host type --- src/sunstone/public/js/plugins/hosts-tab.js | 49 ++++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index 698f923f4b..a5f61fd886 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -31,19 +31,13 @@ var create_host_tmpl = \ \ \ -
\ - \ -
\ -
\ -
\ - \ -
\
\ \ \
\ +
\ +
\ +
\ + \ +
\ +
\ +
\
\
\
\ @@ -84,6 +85,7 @@ var create_host_tmpl = \ \ \ + \ \ \ \ @@ -105,6 +107,7 @@ var create_host_tmpl = \ \ \ + \ \ \ \ @@ -121,6 +124,27 @@ var create_host_tmpl =
\ \
\ + \
\
\ \ @@ -938,8 +962,19 @@ function setupCreateHostDialog(){ $("#im_mad", $create_host_dialog).val(this.value).change(); if (this.value == "custom") { + $(".vcenter_credentials", $create_host_dialog).hide(); + $("#vnm_mads", $create_host_dialog).show(); + $("#create_host_submit", $create_host_dialog).removeAttr("disabled"); $(".drivers", $create_host_dialog).show(); + } else if (this.value == "vcenter") { + $("#vnm_mads", $create_host_dialog).hide(); + $(".vcenter_credentials", $create_host_dialog).show(); + $("#create_host_submit", $create_host_dialog).attr("disabled", "disabled"); + $(".drivers", $create_host_dialog).hide(); } else { + $(".vcenter_credentials", $create_host_dialog).hide(); + $("#vnm_mads", $create_host_dialog).show(); + $("#create_host_submit", $create_host_dialog).removeAttr("disabled"); $(".drivers", $create_host_dialog).hide(); } }) From ad8b7d2c9cd3d73864968f4cfaafb8ce50a0e552 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Thu, 25 Sep 2014 19:36:40 +0200 Subject: [PATCH 25/37] feature #2911: Add vCenter clusters and templates to the host create dialog --- install.sh | 3 +- src/sunstone/etc/sunstone-server.conf | 1 + src/sunstone/public/js/plugins/hosts-tab.js | 180 ++++++++++++++++++-- src/sunstone/routes/vcenter.rb | 89 ++++++++++ 4 files changed, 255 insertions(+), 18 deletions(-) create mode 100644 src/sunstone/routes/vcenter.rb diff --git a/install.sh b/install.sh index e783622f3b..8c6d4300b3 100755 --- a/install.sh +++ b/install.sh @@ -1546,7 +1546,8 @@ SUNSTONE_PUBLIC_JS_PLUGINS_FILES="\ src/sunstone/public/js/plugins/support-tab.js \ src/sunstone/public/js/plugins/zones-tab.js" -SUNSTONE_ROUTES_FILES="src/sunstone/routes/oneflow.rb" +SUNSTONE_ROUTES_FILES="src/sunstone/routes/oneflow.rb \ + src/sunstone/routes/vcenter.rb" # begin bower diff --git a/src/sunstone/etc/sunstone-server.conf b/src/sunstone/etc/sunstone-server.conf index 75b9a70bb4..1a69e29e06 100644 --- a/src/sunstone/etc/sunstone-server.conf +++ b/src/sunstone/etc/sunstone-server.conf @@ -189,3 +189,4 @@ :routes: - oneflow + - vcenter diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index a5f61fd886..82723e5691 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -127,21 +127,33 @@ var create_host_tmpl = \ @@ -955,6 +967,12 @@ function setupCreateHostDialog(){ $create_host_dialog.addClass("reveal-modal medium").attr("data-reveal", ""); $create_host_dialog.foundation() + $("#wizard_host_reset_button", $create_host_dialog).on("click", function(){ + $('#create_host_dialog').html(""); + setupCreateHostDialog(); + popUpCreateHostDialog(); + }) + $(".drivers", $create_host_dialog).hide(); $("#host_type_mad", $create_host_dialog).on("change", function(){ @@ -964,21 +982,149 @@ function setupCreateHostDialog(){ if (this.value == "custom") { $(".vcenter_credentials", $create_host_dialog).hide(); $("#vnm_mads", $create_host_dialog).show(); - $("#create_host_submit", $create_host_dialog).removeAttr("disabled"); + $("#create_host_submit", $create_host_dialog).show(); $(".drivers", $create_host_dialog).show(); } else if (this.value == "vcenter") { $("#vnm_mads", $create_host_dialog).hide(); $(".vcenter_credentials", $create_host_dialog).show(); - $("#create_host_submit", $create_host_dialog).attr("disabled", "disabled"); + $("#create_host_submit", $create_host_dialog).hide(); $(".drivers", $create_host_dialog).hide(); } else { $(".vcenter_credentials", $create_host_dialog).hide(); $("#vnm_mads", $create_host_dialog).show(); - $("#create_host_submit", $create_host_dialog).removeAttr("disabled"); + $("#create_host_submit", $create_host_dialog).show(); $(".drivers", $create_host_dialog).hide(); } }) + $("#get_vcenter_clusters", $create_host_dialog).on("click", function(){ + // TODO notify if credentials empty + $(".vcenter_clusters", $create_host_dialog).html( + ''+ + ''+ + ''+ + '') + + $.ajax({ + url: '/vcenter', + type: "GET", + //data: {timeout: timeout}, + dataType: "json", + headers: { + "X_VCENTER_USER": $("#vcenter_user", $create_host_dialog).val(), + "X_VCENTER_PASSWORD": $("#vcenter_password", $create_host_dialog).val(), + "X_VCENTER_HOST": $("#vcenter_host", $create_host_dialog).val() + }, + success: function(response){ + console.log(response); + $("#get_vcenter_clusters", $create_host_dialog).hide(); + $(".import_vcenter_clusters_div", $create_host_dialog).show(); + + var vcenter_container = $(".vcenter_clusters", $create_host_dialog); + vcenter_container.html(""); + + $('
' + + '
' + + '
' + + datacenter_name + ' ' + tr("Clusters") + + '
' + + '
' + + '
').appendTo(vcenter_container) + + $.each(response, function(datacenter_name, clusters){ + $('
' + + '
' + + '' + tr("Please select the vCenter Clusters and Templates to be imported to OpenNebula. Each vCenter Cluster will be included as a new OpenNebula Host") + '' + + '
' + + '
').appendTo(vcenter_container) + + if (clusters.length == 0) { + $('
' + + '
' + + '' + + '
' + + '
').appendTo(vcenter_container) + } else { + $.each(clusters, function(id, cluster_name){ + var row = $('
' + + '
' + + '
' + + '' + + '
' + + '
'+ + '
'+ + '
'+ + '
').appendTo(vcenter_container) + + $(".cluster_name", row).data("cluster_name", cluster_name) + $(".cluster_name", row).data("datacenter_name", datacenter_name) + $(".cluster_name", row).on("change", function(){ + var path = '/vcenter/' + $(this).data("datacenter_name") + '/cluster/' + $(this).data("cluster_name"); + var templates_container = $(".vcenter_templates", $(this).closest(".vcenter_cluster")) + templates_container.html(generateAdvancedSection({ + html_id: path, + title: tr("Templates"), + content: ''+ + ''+ + ''+ + '' + })) + + $('a', templates_container).trigger("click") + + $.ajax({ + url: path, + type: "GET", + //data: {timeout: timeout}, + dataType: "json", + headers: { + "X_VCENTER_USER": $("#vcenter_user", $create_host_dialog).val(), + "X_VCENTER_PASSWORD": $("#vcenter_password", $create_host_dialog).val(), + "X_VCENTER_HOST": $("#vcenter_host", $create_host_dialog).val() + }, + success: function(response){ + $(".content", templates_container).html(""); + console.log(response); + $.each(response, function(id, template){ + var trow = $('
' + + '
' + + '
' + + '' + + '
' + + '
'+ + '
'+ + '
'+ + '
').appendTo($(".content", templates_container)) + + $(".template_name", trow).data("template_name", template.name) + $(".template_name", trow).data("one_template", template.one) + }); + }, + error: function(response){ + onError({}, OpenNebula.Error(response)); + } + }); + }) + }); + } + }); + }, + error: function(response){ + onError({}, OpenNebula.Error(response)); + } + }); + + return false; + }) + // Show custom driver input only when custom is selected in selects $('input[name="custom_vmm_mad"],'+ 'input[name="custom_im_mad"],'+ @@ -1047,8 +1193,8 @@ function popUpCreateHostDialog(){ insertSelectOptions('#host_cluster_id',$('div#create_host_dialog'), "Cluster", cluster_id, false); - $('div#create_host_dialog').foundation('reveal', 'open'); - $("input#name",$('div#create_host_dialog')).focus(); + $("#create_host_dialog").foundation('reveal', 'open'); + $("input#name",$("#create_host_dialog")).focus(); return false; } diff --git a/src/sunstone/routes/vcenter.rb b/src/sunstone/routes/vcenter.rb new file mode 100644 index 0000000000..8ecf3f6564 --- /dev/null +++ b/src/sunstone/routes/vcenter.rb @@ -0,0 +1,89 @@ +# -------------------------------------------------------------------------- # +# Copyright 2010-2014, C12G Labs S.L. # +# # +# 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. # +#--------------------------------------------------------------------------- # + +if !ONE_LOCATION + REMOTES_LOCATION="/var/lib/one/remotes" +else + REMOTES_LOCATION=ONE_LOCATION+"/var/remotes" +end + +# TODO vcenter_driver should be stored in RUBY_LIB_LOCATION +$: << REMOTES_LOCATION+"/vmm/vcenter/" + +require 'vcenter_driver' + +helpers do + def vcenter_client + vuser = request.env['HTTP_X_VCENTER_USER'] + vpass = request.env['HTTP_X_VCENTER_PASSWORD'] + vhost = request.env['HTTP_X_VCENTER_HOST'] + + if vuser.nil? || vpass.nil? || vhost.nil? + msg = "You have to provide the vCenter username, password and hostname" + logger.error("[vCenter] " + msg) + error = Error.new(msg) + error 404, error.to_json + end + + return VCenterDriver::VIClient.new_connection( + :user => vuser, + :password => vpass, + :host => vhost) + end + +# def af_format_response(resp) +# if CloudClient::is_error?(resp) +# logger.error("[OneFlow] " + resp.to_s) +# +# error = Error.new(resp.to_s) +# error resp.code.to_i, error.to_json +# else +# body resp.body.to_s +# end +# end +end + +get '/vcenter' do + begin + rs = vcenter_client.hierarchy + [200, rs.to_json] + rescue Exception => e + logger.error("[vCenter] " + e.message) + error = Error.new(e.message) + error 403, error.to_json + end +end + +get '/vcenter/:datacenter/cluster/:name' do + begin + rs = vcenter_client.vm_templates + + templates = rs[params[:datacenter]] + if templates.nil? + msg = "Datacenter " + params[:datacenter] + "not found" + logger.error("[vCenter] " + msg) + error = Error.new(msg) + error 404, error.to_json + end + + ctemplates = templates.select{|t| t[:host] == params[:name]} + [200, ctemplates.to_json] + rescue Exception => e + logger.error("[vCenter] " + e.message) + error = Error.new(e.message) + error 403, error.to_json + end +end \ No newline at end of file From 6b78d2a3f3a01197091a37a036adbf3ab7f71764 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 26 Sep 2014 13:08:09 +0200 Subject: [PATCH 26/37] feature #2911: Create hosts and templates from the vCenter dialog --- src/sunstone/public/js/plugins/hosts-tab.js | 244 +++++++++++++++----- 1 file changed, 186 insertions(+), 58 deletions(-) diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index 82723e5691..562315e18d 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -27,10 +27,6 @@ var create_host_tmpl =
\
\
\ -
\ - \ - \ -
\
\ \ \
\ -
\ -
\
\ \
\
\
\ +
\ +
\ +
\ + \ + \ +
\
\
\
\ @@ -982,16 +982,19 @@ function setupCreateHostDialog(){ if (this.value == "custom") { $(".vcenter_credentials", $create_host_dialog).hide(); $("#vnm_mads", $create_host_dialog).show(); + $("#name", $create_host_dialog).show(); $("#create_host_submit", $create_host_dialog).show(); $(".drivers", $create_host_dialog).show(); } else if (this.value == "vcenter") { $("#vnm_mads", $create_host_dialog).hide(); + $("#name", $create_host_dialog).hide(); $(".vcenter_credentials", $create_host_dialog).show(); $("#create_host_submit", $create_host_dialog).hide(); $(".drivers", $create_host_dialog).hide(); } else { $(".vcenter_credentials", $create_host_dialog).hide(); $("#vnm_mads", $create_host_dialog).show(); + $("#name", $create_host_dialog).show(); $("#create_host_submit", $create_host_dialog).show(); $(".drivers", $create_host_dialog).hide(); } @@ -1008,7 +1011,7 @@ function setupCreateHostDialog(){ $.ajax({ url: '/vcenter', type: "GET", - //data: {timeout: timeout}, + data: {timeout: false}, dataType: "json", headers: { "X_VCENTER_USER": $("#vcenter_user", $create_host_dialog).val(), @@ -1017,24 +1020,26 @@ function setupCreateHostDialog(){ }, success: function(response){ console.log(response); + $("#vcenter_user", $create_host_dialog).attr("disabled", "disabled") + $("#vcenter_password", $create_host_dialog).attr("disabled", "disabled") + $("#vcenter_host", $create_host_dialog).attr("disabled", "disabled") $("#get_vcenter_clusters", $create_host_dialog).hide(); $(".import_vcenter_clusters_div", $create_host_dialog).show(); var vcenter_container = $(".vcenter_clusters", $create_host_dialog); vcenter_container.html(""); - $('
' + '
' + - '
' + - datacenter_name + ' ' + tr("Clusters") + - '
' + + '

' + tr("Please select the vCenter Clusters to be imported to OpenNebula. Each vCenter Cluster will be included as a new OpenNebula Host") + '

' + '
' + '
').appendTo(vcenter_container) $.each(response, function(datacenter_name, clusters){ $('
' + '
' + - '' + tr("Please select the vCenter Clusters and Templates to be imported to OpenNebula. Each vCenter Cluster will be included as a new OpenNebula Host") + '' + + '
' + + datacenter_name + ' ' + tr("Clusters") + + '
' + '
' + '
').appendTo(vcenter_container) @@ -1050,12 +1055,16 @@ function setupCreateHostDialog(){ $.each(clusters, function(id, cluster_name){ var row = $('
' + '
' + - '
' + + '
' + '' + + '
'+ + '
'+ '
' + + '
'+ + '
'+ '
'+ '
'+ '
'+ @@ -1064,67 +1073,186 @@ function setupCreateHostDialog(){ $(".cluster_name", row).data("cluster_name", cluster_name) $(".cluster_name", row).data("datacenter_name", datacenter_name) $(".cluster_name", row).on("change", function(){ - var path = '/vcenter/' + $(this).data("datacenter_name") + '/cluster/' + $(this).data("cluster_name"); - var templates_container = $(".vcenter_templates", $(this).closest(".vcenter_cluster")) - templates_container.html(generateAdvancedSection({ - html_id: path, - title: tr("Templates"), - content: ''+ - ''+ - ''+ - '' - })) + var templates_container = $(".vcenter_templates", $(this).closest(".vcenter_cluster")); + if ($(this).is(":checked")) { + var path = '/vcenter/' + $(this).data("datacenter_name") + '/cluster/' + $(this).data("cluster_name"); + templates_container.html(generateAdvancedSection({ + html_id: path, + title: tr("Templates"), + content: ''+ + ''+ + ''+ + '' + })) - $('a', templates_container).trigger("click") + $('a', templates_container).trigger("click") - $.ajax({ - url: path, - type: "GET", - //data: {timeout: timeout}, - dataType: "json", - headers: { - "X_VCENTER_USER": $("#vcenter_user", $create_host_dialog).val(), - "X_VCENTER_PASSWORD": $("#vcenter_password", $create_host_dialog).val(), - "X_VCENTER_HOST": $("#vcenter_host", $create_host_dialog).val() - }, - success: function(response){ - $(".content", templates_container).html(""); - console.log(response); - $.each(response, function(id, template){ - var trow = $('
' + - '
' + - '
' + - '' + - '
' + - '
'+ - '
'+ - '
'+ - '
').appendTo($(".content", templates_container)) + $.ajax({ + url: path, + type: "GET", + data: {timeout: false}, + dataType: "json", + headers: { + "X_VCENTER_USER": $("#vcenter_user", $create_host_dialog).val(), + "X_VCENTER_PASSWORD": $("#vcenter_password", $create_host_dialog).val(), + "X_VCENTER_HOST": $("#vcenter_host", $create_host_dialog).val() + }, + success: function(response){ + $(".content", templates_container).html(""); + console.log(response); + $.each(response, function(id, template){ + var trow = $('
' + + '
' + + '
' + + '' + + '
'+ + '
'+ + '
' + + '
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
').appendTo($(".content", templates_container)) - $(".template_name", trow).data("template_name", template.name) - $(".template_name", trow).data("one_template", template.one) - }); - }, - error: function(response){ + $(".template_name", trow).data("template_name", template.name) + $(".template_name", trow).data("one_template", template.one) + }); + }, + error: function(response){ + templates_container.html(""); onError({}, OpenNebula.Error(response)); - } - }); + } + }); + } else { + templates_container.html(""); + } }) }); } }); }, error: function(response){ - onError({}, OpenNebula.Error(response)); + $(".vcenter_clusters", $create_host_dialog).html('') + onError({}, OpenNebula.Error(response)); } }); return false; }) + + $("#import_vcenter_clusters", $create_host_dialog).on("click", function(){ + $(this).hide(); + + var cluster_id = $('#host_cluster_id .resource_list_select', $create_host_dialog).val(); + if (!cluster_id) cluster_id = "-1"; + + $.each($(".cluster_name:checked", $create_host_dialog), function(){ + console.log($(this).data("cluster_name")); + + var context = $(this).closest(".vcenter_cluster"); + $(".vcenter_host_result:not(.success)", context).html(''+ + ''+ + ''+ + ''); + + var host_json = { + "host": { + "name": $(this).data("cluster_name"), + "vm_mad": "vcenter", + "vnm_mad": "dummy", + "im_mad": "vcenter", + "cluster_id": cluster_id + } + }; + + OpenNebula.Host.create({ + timeout: true, + data: host_json, + success: function (cluster_context){ + return function(request, response) { + $(".vcenter_host_result", cluster_context).addClass("success").html( + ''+ + ''+ + ''+ + ''); + + $(".vcenter_host_response", cluster_context).html('

'+ + tr("Host created successfully")+' ID:'+response.HOST.ID+ + '

'); + + var template_raw = + "VCENTER_USER=\"" + $("#vcenter_user", $create_host_dialog).val() + "\"\n" + + "VCENTER_PASSWORD=\"" + $("#vcenter_password", $create_host_dialog).val() + "\"\n" + + "VCENTER_HOST=\"" + $("#vcenter_host", $create_host_dialog).val() + "\"\n"; + + Sunstone.runAction("Host.update_template", response.HOST.ID, template_raw); + + $.each($(".template_name:checked", cluster_context), function(){ + console.log($(this).data("one_template")); + + var template_context = $(this).closest(".vcenter_template"); + + $(".vcenter_template_result:not(.success)", template_context).html( + ''+ + ''+ + ''+ + ''); + + var template_json = { + "vmtemplate": { + "template_raw": $(this).data("one_template") + } + }; + + OpenNebula.Template.create({ + timeout: true, + data: template_json, + success: function(request, response) { + $(".vcenter_template_result", template_context).addClass("success").html( + ''+ + ''+ + ''+ + ''); + + $(".vcenter_template_response", template_context).html('

'+ + tr("Template created successfully")+' ID:'+response.VMTEMPLATE.ID+ + '

'); + }, + error: function (request, error_json){ + $(".vcenter_template_result", template_context).html(''+ + ''+ + ''+ + ''); + + $(".vcenter_template_response", template_context).html('

'+ + (error_json.error.message || tr("Cannot contact server: is it running and reachable?"))+ + '

'); + } + }); + }) + }; + }(context), + error: function (request, error_json){ + $(".vcenter_host_result", context).html(''+ + ''+ + ''+ + ''); + + $(".vcenter_host_response", context).html('

'+ + (error_json.error.message || tr("Cannot contact server: is it running and reachable?"))+ + '

'); + } + }); + }) + + return false + }); + // Show custom driver input only when custom is selected in selects $('input[name="custom_vmm_mad"],'+ 'input[name="custom_im_mad"],'+ From cac60e589a937ec0669aa6e7eb0792cef711eb2a Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 26 Sep 2014 13:23:15 +0200 Subject: [PATCH 27/37] feature #2911: Remove debugging code --- src/sunstone/public/js/plugins/hosts-tab.js | 114 ++++++++++---------- 1 file changed, 55 insertions(+), 59 deletions(-) diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index 562315e18d..785b5714de 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -1019,7 +1019,6 @@ function setupCreateHostDialog(){ "X_VCENTER_HOST": $("#vcenter_host", $create_host_dialog).val() }, success: function(response){ - console.log(response); $("#vcenter_user", $create_host_dialog).attr("disabled", "disabled") $("#vcenter_password", $create_host_dialog).attr("disabled", "disabled") $("#vcenter_host", $create_host_dialog).attr("disabled", "disabled") @@ -1099,7 +1098,7 @@ function setupCreateHostDialog(){ }, success: function(response){ $(".content", templates_container).html(""); - console.log(response); + $.each(response, function(id, template){ var trow = $('
' + '
' + @@ -1152,10 +1151,8 @@ function setupCreateHostDialog(){ if (!cluster_id) cluster_id = "-1"; $.each($(".cluster_name:checked", $create_host_dialog), function(){ - console.log($(this).data("cluster_name")); - - var context = $(this).closest(".vcenter_cluster"); - $(".vcenter_host_result:not(.success)", context).html(''+ + var cluster_context = $(this).closest(".vcenter_cluster"); + $(".vcenter_host_result:not(.success)", cluster_context).html(''+ ''+ ''+ ''); @@ -1173,70 +1170,69 @@ function setupCreateHostDialog(){ OpenNebula.Host.create({ timeout: true, data: host_json, - success: function (cluster_context){ - return function(request, response) { - $(".vcenter_host_result", cluster_context).addClass("success").html( - ''+ - ''+ - ''+ - ''); + success: function(request, response) { + OpenNebula.Helper.clear_cache("HOST"); - $(".vcenter_host_response", cluster_context).html('

'+ - tr("Host created successfully")+' ID:'+response.HOST.ID+ - '

'); + $(".vcenter_host_result", cluster_context).addClass("success").html( + ''+ + ''+ + ''+ + ''); - var template_raw = - "VCENTER_USER=\"" + $("#vcenter_user", $create_host_dialog).val() + "\"\n" + - "VCENTER_PASSWORD=\"" + $("#vcenter_password", $create_host_dialog).val() + "\"\n" + - "VCENTER_HOST=\"" + $("#vcenter_host", $create_host_dialog).val() + "\"\n"; + $(".vcenter_host_response", cluster_context).html('

'+ + tr("Host created successfully")+' ID:'+response.HOST.ID+ + '

'); - Sunstone.runAction("Host.update_template", response.HOST.ID, template_raw); + var template_raw = + "VCENTER_USER=\"" + $("#vcenter_user", $create_host_dialog).val() + "\"\n" + + "VCENTER_PASSWORD=\"" + $("#vcenter_password", $create_host_dialog).val() + "\"\n" + + "VCENTER_HOST=\"" + $("#vcenter_host", $create_host_dialog).val() + "\"\n"; - $.each($(".template_name:checked", cluster_context), function(){ - console.log($(this).data("one_template")); + Sunstone.runAction("Host.update_template", response.HOST.ID, template_raw); - var template_context = $(this).closest(".vcenter_template"); + $.each($(".template_name:checked", cluster_context), function(){ + var template_context = $(this).closest(".vcenter_template"); - $(".vcenter_template_result:not(.success)", template_context).html( + $(".vcenter_template_result:not(.success)", template_context).html( + ''+ + ''+ + ''+ + ''); + + var template_json = { + "vmtemplate": { + "template_raw": $(this).data("one_template") + } + }; + + OpenNebula.Template.create({ + timeout: true, + data: template_json, + success: function(request, response) { + OpenNebula.Helper.clear_cache("VMTEMPLATE"); + $(".vcenter_template_result", template_context).addClass("success").html( ''+ ''+ - ''+ + ''+ ''); - var template_json = { - "vmtemplate": { - "template_raw": $(this).data("one_template") - } - }; + $(".vcenter_template_response", template_context).html('

'+ + tr("Template created successfully")+' ID:'+response.VMTEMPLATE.ID+ + '

'); + }, + error: function (request, error_json){ + $(".vcenter_template_result", template_context).html(''+ + ''+ + ''+ + ''); - OpenNebula.Template.create({ - timeout: true, - data: template_json, - success: function(request, response) { - $(".vcenter_template_result", template_context).addClass("success").html( - ''+ - ''+ - ''+ - ''); - - $(".vcenter_template_response", template_context).html('

'+ - tr("Template created successfully")+' ID:'+response.VMTEMPLATE.ID+ - '

'); - }, - error: function (request, error_json){ - $(".vcenter_template_result", template_context).html(''+ - ''+ - ''+ - ''); - - $(".vcenter_template_response", template_context).html('

'+ - (error_json.error.message || tr("Cannot contact server: is it running and reachable?"))+ - '

'); - } - }); - }) - }; - }(context), + $(".vcenter_template_response", template_context).html('

'+ + (error_json.error.message || tr("Cannot contact server: is it running and reachable?"))+ + '

'); + } + }); + }) + }, error: function (request, error_json){ $(".vcenter_host_result", context).html(''+ ''+ From 3872deb3e824adc5cf407202ad69dd0b59da260a Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 26 Sep 2014 16:53:13 +0200 Subject: [PATCH 28/37] feature #2911: Add ESX list to the host info --- src/sunstone/public/js/plugins/hosts-tab.js | 74 +++++++++++++++++---- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index 785b5714de..7215f160f5 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -181,10 +181,6 @@ var host_actions = { call : OpenNebula.Host.create, callback : function(request, response) { // Reset the create wizard - $create_host_dialog.foundation('reveal', 'close'); - $create_host_dialog.empty(); - setupCreateHostDialog(); - addHostElement(request, response); notifyCustom(tr("Host created"), " ID: " + response.HOST.ID, false); }, @@ -467,12 +463,13 @@ function hostElements(){ return getSelectedNodes(dataTable_hosts); } -function generateCPUProgressBar(host) { - var max_cpu = parseInt(host.HOST_SHARE.MAX_CPU); +function generateCPUProgressBar(host, host_share_flag) { + var host_share = host_share_flag ? host : host.HOST_SHARE; + var max_cpu = parseInt(host_share.MAX_CPU); var info_str; - var allocated_cpu = parseInt(host.HOST_SHARE.CPU_USAGE); + var allocated_cpu = parseInt(host_share.CPU_USAGE); if (max_cpu > 0) { var ratio_allocated_cpu = Math.round((allocated_cpu / max_cpu) * 100); @@ -483,7 +480,7 @@ function generateCPUProgressBar(host) { var pb_allocated_cpu = quotaBarHtml(allocated_cpu, max_cpu, info_str); - var real_cpu = parseInt(host.HOST_SHARE.USED_CPU); + var real_cpu = parseInt(host_share.USED_CPU); if (max_cpu > 0) { var ratio_real_cpu = Math.round((real_cpu / max_cpu) * 100); @@ -500,11 +497,12 @@ function generateCPUProgressBar(host) { } } -function generateMEMProgressBar(host){ +function generateMEMProgressBar(host, host_share_flag) { + var host_share = host_share_flag ? host : host.HOST_SHARE; // Generate MEM progress bars - var max_mem = parseInt(host.HOST_SHARE.MAX_MEM); + var max_mem = parseInt(host_share.MAX_MEM); - var allocated_mem = parseInt(host.HOST_SHARE.MEM_USAGE); + var allocated_mem = parseInt(host_share.MEM_USAGE); if (max_mem > 0) { var ratio_allocated_mem = Math.round((allocated_mem / max_mem) * 100); @@ -515,7 +513,7 @@ function generateMEMProgressBar(host){ var pb_allocated_mem = quotaBarHtml(allocated_mem, max_mem, info_str); - var real_mem = parseInt(host.HOST_SHARE.USED_MEM); + var real_mem = parseInt(host_share.USED_MEM); if (max_mem > 0) { var ratio_real_mem = Math.round((real_mem / max_mem) * 100); @@ -895,13 +893,60 @@ function updateHostInfo(request,host){
' } + var esx_info_tab = { + title: tr("ESX"), + icon: "fa-hdd-o", + content : '
\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
' + tr("Hostname") + '' + tr("Status") + '
\ +
\ +
' + } + //Sunstone.updateInfoPanelTab(info_panel_name,tab_name, new tab object); Sunstone.updateInfoPanelTab("host_info_panel","host_info_tab",info_tab); Sunstone.updateInfoPanelTab("host_info_panel","host_monitoring_tab",monitor_tab); Sunstone.updateInfoPanelTab("host_info_panel","host_vms_tab",vms_info_tab); + if (host_info.TEMPLATE.HYPERVISOR == "vcenter") { + Sunstone.updateInfoPanelTab("host_info_panel","host_esx_tab",esx_info_tab); + } + Sunstone.popUpInfoPanel("host_info_panel", "hosts-tab"); + if (host_info.TEMPLATE.HYPERVISOR == "vcenter") { + var dataTable_esx_hosts = $("#datatable_host_esx",main_tabs_context).dataTable({ + "bSortClasses" : false, + "bDeferRender": true + }); + + var host_list_array = []; + $.each(host_info.TEMPLATE.HOST, function(){ + // TODO HOST (esx) keys should match HOST_SHARE keys (FREECPU vs FREE_CPU | TOTAL vs MAX) + //var cpu_bars = generateCPUProgressBar(this, true); + //var mem_bars = generateMEMProgressBar(this, true); + host_list_array.push([ + this.HOSTNAME, + //cpu_bars.real, + //cpu_bars.allocated, + //mem_bars.real, + //mem_bars.allocated, + this.STATE + ]); + }); + dataTable_esx_hosts.fnAddData(host_list_array); + delete host_info.TEMPLATE.HOST; + } + var dataTable_host_vMachines = $("#datatable_host_vms", $("#host_info_panel")).dataTable({ "bSortClasses" : false, "bDeferRender": true, @@ -1189,6 +1234,7 @@ function setupCreateHostDialog(){ "VCENTER_HOST=\"" + $("#vcenter_host", $create_host_dialog).val() + "\"\n"; Sunstone.runAction("Host.update_template", response.HOST.ID, template_raw); + addHostElement(request, response); $.each($(".template_name:checked", cluster_context), function(){ var template_context = $(this).closest(".vcenter_template"); @@ -1312,6 +1358,10 @@ function setupCreateHostDialog(){ //Open creation dialogs function popUpCreateHostDialog(){ + $create_host_dialog.foundation('reveal', 'close'); + $create_host_dialog.empty(); + setupCreateHostDialog(); + var cluster_id = $('#host_cluster_id .resource_list_select',$('div#create_host_dialog')).val(); if (!cluster_id) cluster_id = "-1"; From 3ab34851fbc72d5e61d846dc03f22403e422534d Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 26 Sep 2014 18:22:26 +0200 Subject: [PATCH 29/37] feature #2911: Solve snapshot bugs in vCenter --- src/vmm_mad/remotes/vcenter/snapshot_create | 4 ++-- src/vmm_mad/remotes/vcenter/snapshot_revert | 2 +- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index cc89040dc0..9912df4db9 100644 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -34,8 +34,8 @@ snapshot_name = ARGV[1] host = ARGV[3] begin - VCenterDriver::VCenterVm.create_snapshot(deploy_id, - host, + puts VCenterDriver::VCenterVm.create_snapshot(deploy_id, + host, snapshot_name) rescue Exception => e STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} failed " + diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index fa96fc4e6e..372ce44c32 100644 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -38,7 +38,7 @@ begin host, snapshot_name) rescue Exception => e - STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} could not be " + + STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} could not be " + "reverted due to \"#{e.message}\"" exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 6b3c57503e..ac52879fb0 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -560,6 +560,8 @@ class VCenterVm vm = connection.find_vm_template(deploy_id) vm.CreateSnapshot_Task(snapshot_hash).wait_for_completion + + return snapshot_name end ############################################################################ @@ -583,7 +585,7 @@ class VCenterVm :removeChildren => true } - vm.RemoveSnapshot_Task(delete_snapshot_hash).wait_for_completion + snapshot.RemoveSnapshot_Task(delete_snapshot_hash).wait_for_completion end ############################################################################ @@ -606,7 +608,7 @@ class VCenterVm :_this => snapshot } - vm.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion + snapshot.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion end ######################################################################## From 5dccdb7e2350ee4e4084d626f3cc2185b1b90a31 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 26 Sep 2014 19:40:38 +0200 Subject: [PATCH 30/37] feature #2911: Remove unneeded cancel feedback --- 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 d41f78ef26..6a524f5ec9 100644 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -39,7 +39,7 @@ vm.info lcm_state = vm.lcm_state_str begin - puts VCenterDriver::VCenterVm.cancel(deploy_id, host, lcm_state) + VCenterDriver::VCenterVm.cancel(deploy_id, host, lcm_state) rescue Exception => e STDERR.puts "Cancel of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" From 7f1b1d32b41237e96b323a2dfd68bda10e3902b9 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 26 Sep 2014 19:41:59 +0200 Subject: [PATCH 31/37] Feature #2911: Fix cancel race condition --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index ac52879fb0..83b7ef565d 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -440,7 +440,7 @@ class VCenterVm case lcm_state when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" shutdown(deploy_id, hostname, lcm_state) - when "CANCEL" + when "CANCEL", "LCM_INIT" hid = VIClient::translate_hostname(hostname) connection = VIClient.new(hid) vm = connection.find_vm_template(deploy_id) From d62b7335fa6d7306bbdac086096386279585b3b9 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Mon, 29 Sep 2014 10:09:50 +0200 Subject: [PATCH 32/37] feature #2911: removed unneeded file from install.sh --- install.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/install.sh b/install.sh index 8c6d4300b3..d036f0a3de 100755 --- a/install.sh +++ b/install.sh @@ -783,7 +783,6 @@ VMM_EXEC_VCENTER_SCRIPTS="src/vmm_mad/remotes/vcenter/cancel \ src/vmm_mad/remotes/vcenter/reset \ src/vmm_mad/remotes/vcenter/save \ src/vmm_mad/remotes/vcenter/poll \ - src/vmm_mad/remotes/vcenter/checkpoint \ src/vmm_mad/remotes/vcenter/shutdown \ src/vmm_mad/remotes/vcenter/vcenter_driver.rb" From 9765db73e0fcd21adca980857c61d0c28948adbd Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 29 Sep 2014 10:13:27 +0200 Subject: [PATCH 33/37] feature #2911: Add support to optionally execute the same action more than once in a host --- src/mad/ruby/ActionManager.rb | 22 ++++++++--------- src/mad/ruby/VirtualMachineDriver.rb | 36 +++++++++++++++++++++++++++- src/vmm_mad/exec/one_vmm_exec.rb | 9 +++++-- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/mad/ruby/ActionManager.rb b/src/mad/ruby/ActionManager.rb index 2116a3ff65..7a6f6342e9 100644 --- a/src/mad/ruby/ActionManager.rb +++ b/src/mad/ruby/ActionManager.rb @@ -112,7 +112,7 @@ class ActionManager end arity=@actions[aname][:method].arity - + if arity < 0 # Last parameter is an array arity = -arity - 1 @@ -145,7 +145,7 @@ class ActionManager else thread = nil end - + if thread thread.kill @@ -173,17 +173,17 @@ class ActionManager } end end - -private - + + protected + def delete_running_action(action_id) @action_running.delete(action_id) end - + def get_runable_action @action_queue.shift end - + def empty_queue @action_queue.size==0 end @@ -228,13 +228,13 @@ if __FILE__ == $0 @am.register_action(:SLEEP,method("sleep_action")) # @am.register_action(:SLEEP,Proc.new{|s,i| p s ; sleep(s)}) @am.register_action(:NOP,method("nop_action")) - + def @am.get_runable_action action = super puts "getting: #{action.inspect}" action end - + def @am.delete_running_action(action_id) puts "deleting: #{action_id}" super(action_id) @@ -250,7 +250,7 @@ if __FILE__ == $0 def nop_action p " - Just an action" end - + end s = Sample.new @@ -264,7 +264,7 @@ if __FILE__ == $0 } s.am.trigger_action(:SLEEP,301,5,301) - + s.am.cancel_action(301) s.am.trigger_action(:FINALIZE,0) diff --git a/src/mad/ruby/VirtualMachineDriver.rb b/src/mad/ruby/VirtualMachineDriver.rb index ca12065426..21f00cfc2d 100644 --- a/src/mad/ruby/VirtualMachineDriver.rb +++ b/src/mad/ruby/VirtualMachineDriver.rb @@ -77,7 +77,8 @@ class VirtualMachineDriver < OpenNebulaDriver # @option options [Boolean] :threaded (true) enables or disables threads def initialize(directory, options={}) @options={ - :threaded => true + :threaded => true, + :single_host => true }.merge!(options) super(directory, @options) @@ -214,8 +215,17 @@ class VirtualMachineDriver < OpenNebulaDriver end private + # Interface to handle the pending events from the ActionManager Interface def delete_running_action(action_id) + if @options[:single_host] + delete_running_action_single_host(action_id) + else + super(action_id) + end + end + + def delete_running_action_single_host(action_id) action=@action_running[action_id] if action @hosts.delete(action[:host]) @@ -224,6 +234,14 @@ private end def get_first_runable + if @options[:single_host] + get_first_runable_single_host + else + super + end + end + + def get_first_runable_single_host action_index=nil @action_queue.each_with_index do |action, index| if !action.keys.include?(:host) @@ -255,6 +273,14 @@ private end def get_runable_action + if @options[:single_host] + get_runable_action_single_host + else + super + end + end + + def get_runable_action_single_host action_index=get_first_runable if action_index @@ -272,6 +298,14 @@ private end def empty_queue + if @options[:single_host] + empty_queue_single_host + else + super + end + end + + def empty_queue_single_host get_first_runable==nil end end diff --git a/src/vmm_mad/exec/one_vmm_exec.rb b/src/vmm_mad/exec/one_vmm_exec.rb index f2e4e6c5cb..500fa14f16 100755 --- a/src/vmm_mad/exec/one_vmm_exec.rb +++ b/src/vmm_mad/exec/one_vmm_exec.rb @@ -901,7 +901,8 @@ opts = GetoptLong.new( [ '--retries', '-r', GetoptLong::OPTIONAL_ARGUMENT ], [ '--threads', '-t', GetoptLong::OPTIONAL_ARGUMENT ], [ '--local', '-l', GetoptLong::REQUIRED_ARGUMENT ], - [ '--shell', '-s', GetoptLong::REQUIRED_ARGUMENT ] + [ '--shell', '-s', GetoptLong::REQUIRED_ARGUMENT ], + [ '--parallel' '-p', GetoptLong::REQUIRED_ARGUMENT ] ) hypervisor = '' @@ -909,6 +910,7 @@ retries = 0 threads = 15 shell = 'bash' local_actions = {} +single_host = true begin opts.each do |opt, arg| @@ -921,6 +923,8 @@ begin local_actions=OpenNebulaDriver.parse_actions_list(arg) when '--shell' shell = arg + when '--parallel' + single_host = false end end rescue Exception => e @@ -937,6 +941,7 @@ exec_driver = ExecDriver.new(hypervisor, :concurrency => threads, :retries => retries, :local_actions => local_actions, - :shell => shell) + :shell => shell, + :single_host => single_host) exec_driver.start_driver From 7f6bf133ece6a2925f3fa34c33f00302d8d9671e Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 29 Sep 2014 10:17:32 +0200 Subject: [PATCH 34/37] feature #2911: -p does not need argument --- src/vmm_mad/exec/one_vmm_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/exec/one_vmm_exec.rb b/src/vmm_mad/exec/one_vmm_exec.rb index 500fa14f16..2edf1b4c17 100755 --- a/src/vmm_mad/exec/one_vmm_exec.rb +++ b/src/vmm_mad/exec/one_vmm_exec.rb @@ -902,7 +902,7 @@ opts = GetoptLong.new( [ '--threads', '-t', GetoptLong::OPTIONAL_ARGUMENT ], [ '--local', '-l', GetoptLong::REQUIRED_ARGUMENT ], [ '--shell', '-s', GetoptLong::REQUIRED_ARGUMENT ], - [ '--parallel' '-p', GetoptLong::REQUIRED_ARGUMENT ] + [ '--parallel' '-p', GetoptLong::NO_ARGUMENT ] ) hypervisor = '' From 59492736c8304fac01c39a97187fc6ca05c07c62 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Mon, 29 Sep 2014 11:11:43 +0200 Subject: [PATCH 35/37] feature #2911: Add concurrency to vCenter driver --- share/etc/oned.conf | 2 +- src/vmm_mad/exec/one_vmm_exec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/etc/oned.conf b/share/etc/oned.conf index b3c6cbb6b6..683760a3e0 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -451,7 +451,7 @@ VM_MAD = [ #VM_MAD = [ # name = "vcenter", # executable = "one_vmm_sh", -# arguments = "-t 15 -r 0 vcenter -s sh", +# arguments = "-p -t 15 -r 0 vcenter -s sh", # type = "xml" ] #------------------------------------------------------------------------------- diff --git a/src/vmm_mad/exec/one_vmm_exec.rb b/src/vmm_mad/exec/one_vmm_exec.rb index 2edf1b4c17..3d7fbcc8d4 100755 --- a/src/vmm_mad/exec/one_vmm_exec.rb +++ b/src/vmm_mad/exec/one_vmm_exec.rb @@ -902,7 +902,7 @@ opts = GetoptLong.new( [ '--threads', '-t', GetoptLong::OPTIONAL_ARGUMENT ], [ '--local', '-l', GetoptLong::REQUIRED_ARGUMENT ], [ '--shell', '-s', GetoptLong::REQUIRED_ARGUMENT ], - [ '--parallel' '-p', GetoptLong::NO_ARGUMENT ] + [ '--parallel', '-p', GetoptLong::NO_ARGUMENT ] ) hypervisor = '' From 25c252bbba10da69a40d9ded66af2082087c0cd9 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Mon, 29 Sep 2014 12:53:15 +0200 Subject: [PATCH 36/37] feature #2911: change monitor attributes keys for ESX hosts within vCenter to ease Sunstone integration --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 83b7ef565d..71a0d08a1c 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -359,12 +359,12 @@ class VCenterHost < ::OpenNebula::Host host_info << "HOSTNAME=\"" << h.name.to_s << "\"," host_info << "MODELNAME=\"" << hw.cpuModel.to_s << "\"," host_info << "CPUSPEED=" << hw.cpuMhz.to_s << "," - host_info << "TOTALCPU=" << total_cpu.to_s << "," - host_info << "USEDCPU=" << used_cpu.to_s << "," - host_info << "FREECPU=" << free_cpu.to_s << "," - host_info << "TOTALMEMORY=" << total_memory.to_s << "," - host_info << "USEDMEMORY=" << used_memory.to_s << "," - host_info << "FREEMEMORY=" << 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_MEMORY=" << total_memory.to_s << "," + host_info << "USED_MEMORY=" << used_memory.to_s << "," + host_info << "FREE_MEMORY=" << free_memory.to_s host_info << "]" } From 88fdcb3536486b00b4a591f252d47b7b06309d3a Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Mon, 29 Sep 2014 17:39:35 +0200 Subject: [PATCH 37/37] feature #2911: Add vCenter type to the template form --- .../public/js/plugins/templates-tab.js | 60 +++++++++++++------ src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 1 + 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/sunstone/public/js/plugins/templates-tab.js b/src/sunstone/public/js/plugins/templates-tab.js index f62001a12a..97a8d5abdc 100644 --- a/src/sunstone/public/js/plugins/templates-tab.js +++ b/src/sunstone/public/js/plugins/templates-tab.js @@ -784,16 +784,17 @@ function generate_capacity_tab_content() { ''+ ''+ ''+ + ''+ '
'+ '
'+ '
'+ - '
'+ + '
'+ ''+ '