Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
283 lines (241 sloc) 11 KB
###################################
#
# EVM Automate Method: best_fit_with_scope
#
# Notes: This method is used to find all hosts, datastores that have the tag category
# prov_scope = 'all' &&|| prov_scope = <group-name>
#
###################################
begin
@method = 'best_fit_with_scope'
$evm.log("info", "#{@method} - EVM Automate Method: <#{@method}> Started")
# Turn of verbose logging
@debug = true
#
# Get variables
#
prov = $evm.root["miq_provision"]
vm = prov.vm_template
raise "#{@method} - VM not specified" if vm.nil?
user = prov.miq_request.requester
raise "#{@method} - User not specified" if user.nil?
ems = vm.ext_management_system
raise "#{@method} - EMS not found for VM:<#{vm.name}>" if ems.nil?
# Log all provisioning options and space required
#$evm.log("info", "Inspecting provisioning object: #{prov.options.inspect}") if @debug
#$evm.log("info", "VM=<#{vm.name}>, Space Required=<#{vm.provisioned_storage}>")
attrs = $evm.object.attributes
tags = {}
#############################
# Get Tags that are in scope
# Default is to look for Hosts and Datastores tagged with prov_scope = All or match to Group
#############################
tags["prov_scope"] = ["all",user.normalized_ldap_group]
$evm.log("info", "#{@method} - VM=<#{vm.name}>, Space Required=<#{vm.provisioned_storage}>, group=<#{user.normalized_ldap_group}>") if @debug
#############################
# STORAGE LIMITATIONS
#############################
STORAGE_MAX_VMS = 0
storage_max_vms = $evm.object['storage_max_vms']
storage_max_vms = storage_max_vms.strip.to_i if storage_max_vms.kind_of?(String) && !storage_max_vms.strip.empty?
storage_max_vms = STORAGE_MAX_VMS unless storage_max_vms.kind_of?(Numeric)
STORAGE_MAX_PCT_USED = 100
storage_max_pct_used = $evm.object['storage_max_pct_used']
storage_max_pct_used = storage_max_pct_used.strip.to_i if storage_max_pct_used.kind_of?(String) && !storage_max_pct_used.strip.empty?
storage_max_pct_used = STORAGE_MAX_PCT_USED unless storage_max_pct_used.kind_of?(Numeric)
$evm.log("info","#{@method} - storage_max_vms:<#{storage_max_vms}> storage_max_pct_used:<#{storage_max_pct_used}>") if @debug
#############################
# Set host sort order here
# options: :active_provioning_memory, :active_provioning_cpu, :current_memory_usage,
# :current_memory_headroom, :current_cpu_usage, :random
#############################
HOST_SORT_ORDER = [:active_provioning_memory, :current_memory_headroom, :random]
#############################
# Sort hosts
#############################
active_prov_data = prov.check_quota(:active_provisions)
sort_data = []
ems.hosts.each do |h|
sort_data << sd = [[], h.name, h]
host_id = h.attributes['id'].to_i
HOST_SORT_ORDER.each do |type|
sd[0] << case type
# Multiply values by (-1) to cause larger values to sort first
when :active_provioning_memory
active_prov_data[:active][:memory_by_host_id][host_id]
when :active_provioning_cpu
active_prov_data[:active][:cpu_by_host_id][host_id]
when :current_memory_headroom
h.current_memory_headroom * -1
when :current_memory_usage
h.current_memory_usage
when :current_cpu_usage
h.current_cpu_usage
when :random
rand(1000)
else 0
end
##### End sort options
end
end
sort_data.sort! {|a,b| a[0] <=> b[0]}
hosts = sort_data.collect {|sd| sd.pop}
$evm.log("info", "#{@method} - Sorted host Order:<#{HOST_SORT_ORDER.inspect}> Results:<#{sort_data.inspect}>") if @debug
#############################
# Set storage sort order here
# options: :active_provisioning_vms, :free_space, :free_space_percentage, :random
#############################
STORAGE_SORT_ORDER = [:active_provisioning_vms, :random]
host = storage = nil
min_registered_vms = nil
hosts.each do |h|
next unless h.power_state == "on"
#############################
# Only consider hosts that have the required tags
#############################
next unless tags.all? do |key, value|
if value.kind_of?(Array)
value.any? { |v| h.tagged_with?(key, v) }
else
h.tagged_with?(key, value)
end
end
#############################
# Drop out any hosts that contain virtual machines tagged with xxxxxx
#############################
provTags = prov.get_tag(:excludeworkload)
$evm.log("info","--- PROVISIONING TAGS --- #{provTags}")
dropout = false
$evm.log("info","========== #{h.name}")
h.vms.each do | vm |
$evm.log("info","----------VM Found : #{vm.name}")
vm.tags.each do | key,value |
if key.split('/')[1] == provTags
$evm.log("info","---------Tag Found : #{key}")
$evm.log("info","---------Excluding Host : #{h.name}")
dropout = true
end
end
end
$evm.log("info", "=====DROPOUT==== #{dropout}")
next unless dropout == false
nvms = h.vms.length
#############################
# Only consider storages that have the tag category group=all
#############################
storages = h.storages.find_all do |s|
tags.all? do |key, value|
if value.kind_of?(Array)
value.any? { |v| s.tagged_with?(key, v) }
else
s.tagged_with?(key, value)
end
end
end
$evm.log("info", "#{@method} - Evaluating storages:<#{storages.collect {|s| s.name}.join(", ")}>") if @debug
#############################
# Filter out storages that do not have enough free space for the VM
#############################
active_prov_data = prov.check_quota(:active_provisions)
storages = storages.find_all { |s|
storage_id = s.attributes['id'].to_i
actively_provisioned_space = active_prov_data[:active][:storage_by_id][storage_id]
if s.free_space > vm.provisioned_storage + actively_provisioned_space
# $evm.log("info", "Active Provision Data inspect: [#{active_prov_data.inspect}]")
# $evm.log("info", "Active provision space requirement: [#{actively_provisioned_space}]")
# $evm.log("info", "Valid Datastore: [#{s.name}], enough free space for VM -- Available: [#{s.free_space}], Needs: [#{vm.provisioned_storage}]")
true
else
$evm.log("info", "#{@method} - Skipping Datastore:<#{s.name}>, not enough free space for VM:<#{vm.name}>. Available:<#{s.free_space}>, Needs:<#{vm.provisioned_storage}>") if @debug
false
end
}
#############################
# Filter out storages number of VMs is greater than the max number of VMs allowed per Datastore
#############################
storages = storages.find_all { |s|
storage_id = s.attributes['id'].to_i
active_num_vms_for_storage = active_prov_data[:active][:vms_by_storage_id][storage_id].length
if (storage_max_vms == 0) || ((s.vms.size + active_num_vms_for_storage) < storage_max_vms)
true
else
$evm.log("info", "#{@method} - Skipping Datastore:<#{s.name}>, max number of VMs:<#{s.vms.size + active_num_vms_for_storage}> exceeded") if @debug
false
end
}
#############################
# Filter out storages where percent used will be greater than the max % allowed per Datastore
#############################
storages = storages.find_all { |s|
storage_id = s.attributes['id'].to_i
active_pct_of_storage = ((active_prov_data[:active][:storage_by_id][storage_id]) / s.total_space.to_f) * 100
request_pct_of_storage = (vm.provisioned_storage / s.total_space.to_f) * 100
# $evm.log("info", "Active Provision Data inspect: [#{s.name}]:[#{storage_id}] -- [#{active_prov_data.inspect}]")
# $evm.log("info", "Datastore Percent: [#{s.name}]:[#{storage_id}] -- Storage:[#{s.v_used_space_percent_of_total}] Active:[#{active_pct_of_storage}] Request:[#{request_pct_of_storage}]")
if (storage_max_pct_used == 100) || ((s.v_used_space_percent_of_total + active_pct_of_storage + request_pct_of_storage) < storage_max_pct_used)
# $evm.log("info", "Current PCT of active provision: [#{active_pct_of_storage}]")
# $evm.log("info", "Valid Datastore: [#{s.name}], enough free space for VM -- Total Datastore Size: [#{s.total_space}], Available: [#{s.free_space}], Needs: [#{vm.provisioned_storage}]")
true
else
$evm.log("info", "#{@method} - Skipping Datastore:<#{s.name}> percent of used space #{s.v_used_space_percent_of_total + active_pct_of_storage + request_pct_of_storage} exceeded") if @debug
# $evm.log("info", "Total Datastore Size: [#{s.total_space}], Total Percentage Required: ([#{s.v_used_space_percent_of_total}] + [#{active_pct_of_storage}])")
false
end
}
if min_registered_vms.nil? || nvms < min_registered_vms
#############################
# Sort storage to determine target datastore
#############################
sort_data = []
storages.each_with_index do |s, idx|
sort_data << sd = [[], s.name, idx]
storage_id = s.attributes['id'].to_i
STORAGE_SORT_ORDER.each do |type|
sd[0] << case type
when :free_space
# Multiply values by (-1) to cause larger values to sort first
(s.free_space - active_prov_data[:active][:storage_by_id][storage_id]) * -1
when :free_space_percentage
active_pct_of_storage = ((active_prov_data[:active][:storage_by_id][storage_id]) / s.total_space.to_f) * 100
s.v_used_space_percent_of_total + active_pct_of_storage
when :active_provioning_vms
active_prov_data[:active][:vms_by_storage_id][storage_id].length
when :random
rand(1000)
else 0
end
##### End sort options
end
end
sort_data.sort! {|a,b| a[0] <=> b[0]}
$evm.log("info", "#{@method} - Sorted storage Order:<#{STORAGE_SORT_ORDER.inspect}> Results:<#{sort_data.inspect}>") if @debug
selected_storage = sort_data.first
unless selected_storage.nil?
selected_idx = selected_storage.last
storage = storages[selected_idx]
host = h
end
$evm.log("info", "Found Host:<#{h.name}> with Tags:<#{h.tags.inspect}>") if @debug
# Stop checking if we have found both host and storage
break if host && storage
end
end # END - hosts.each
obj = $evm.object
$evm.log("info", "#{@method} - Selected Host:<#{host.nil? ? "nil" : host.name}>") if @debug
obj["host"] = host unless host.nil?
$evm.log("info", "#{@method} - Selected Datastore:<#{storage.nil? ? "nil" : storage.name}>") if @debug
obj["storage"] = storage unless storage.nil?
# Set host and storage
$evm.log("info", "#{@method} - vm=<#{vm.name}> host=<#{host}> storage=<#{storage}>") if @debug
#
# Exit method
#
$evm.log("info", "#{@method} - EVM Automate Method Ended")
exit MIQ_OK
#
# Set Ruby rescue behavior
#
rescue => err
$evm.log("error", "#{@method} - [#{err}]\n#{err.backtrace.join("\n")}")
exit MIQ_ABORT
end