Skip to content

Commit

Permalink
Add VmMigrationValidator.
Browse files Browse the repository at this point in the history
  • Loading branch information
lfu committed Sep 13, 2018
1 parent 9f3c401 commit 6d77f74
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 165 deletions.
129 changes: 3 additions & 126 deletions app/models/transformation_mapping.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
class TransformationMapping < ApplicationRecord
VM_CONFLICT = "conflict".freeze
VM_EMPTY_NAME = "empty_name".freeze
VM_IN_OTHER_PLAN = "in_other_plan".freeze
VM_MIGRATED = "migrated".freeze
VM_NOT_EXIST = "not_exist".freeze
VM_VALID = "ok".freeze
VM_INACTIVE = "inactive".freeze
require_nested :VmMigrationValidator

has_many :transformation_mapping_items, :dependent => :destroy
has_many :service_resources, :as => :resource, :dependent => :nullify
Expand All @@ -18,124 +12,7 @@ def destination(source)
end

# vm_list: collection of hashes, each descriping a VM.
def validate_vms(vm_list = nil)
vm_list.present? ? identify_vms(vm_list) : select_vms
end

private

def select_vms
valid_list = []

transformation_mapping_items.where(:source_type => EmsCluster).collect(&:source).each do |cluster|
cluster.vms.each do |vm|
reason = validate_vm(vm, true)
valid_list << describe_vm(vm, reason) if reason == VM_VALID
end
end

{"valid_vms" => valid_list}
end

def identify_vms(vm_list)
valid_list = []
invalid_list = []
conflict_list = []

vm_list.each do |row|
vm_name = row['name']

if vm_name.blank?
invalid_list << describe_non_vm(vm_name)
next
end

query = Vm.where(:name => vm_name)
query = query.where(:uid_ems => row['uid_ems']) if row['uid_ems'].present?
query = query.joins(:host).where(:hosts => {:name => row['host']}) if row['host'].present?
query = query.joins(:ext_management_system).where(:ext_management_systems => {:name => row['provider']}) if row['provider'].present?

vms = query.to_a
if vms.size.zero?
invalid_list << describe_non_vm(vm_name)
elsif vms.size == 1
reason = validate_vm(vms.first, false)
(reason == VM_VALID ? valid_list : invalid_list) << describe_vm(vms.first, reason)
else
vms.each { |vm| conflict_list << describe_vm(vm, VM_CONFLICT) }
end
end

{
"valid_vms" => valid_list,
"invalid_vms" => invalid_list,
"conflict_vms" => conflict_list
}
end

def describe_non_vm(vm_name)
{
"name" => vm_name,
"reason" => vm_name.blank? ? VM_EMPTY_NAME : VM_NOT_EXIST
}
end

def describe_vm(vm, reason)
{
"name" => vm.name,
"cluster" => vm.ems_cluster.try(:name) || '',
"path" => vm.ext_management_system ? "#{vm.ext_management_system.name}/#{vm.v_parent_blue_folder_display_path}" : '',
"allocated_size" => vm.allocated_disk_storage,
"id" => vm.id,
"ems_cluster_id" => vm.ems_cluster_id,
"reason" => reason
}
end

def validate_vm(vm, quick = true)
validate_result = vm.validate_v2v_migration
return validate_result unless validate_result == VM_VALID

# a valid vm must find all resources in the mapping and has never been migrated
invalid_list = []

unless valid_cluster?(vm)
invalid_list << "cluster: %{name}" % {:name => vm.ems_cluster.name}
return no_mapping_msg(invalid_list) if quick
end

invalid_storages = unmapped_storages(vm)
if invalid_storages.present?
invalid_list << "storages: %{list}" % {:list => invalid_storages.collect(&:name).join(", ")}
return no_mapping_msg(invalid_list) if quick
end

invalid_lans = unmapped_lans(vm)
if invalid_lans.present?
invalid_list << "lans: %{list}" % {:list => invalid_lans.collect(&:name).join(', ')}
return no_mapping_msg(invalid_list) if quick
end

invalid_list.present? ? no_mapping_msg(invalid_list) : VM_VALID
end

def no_mapping_msg(list)
"Mapping source not found - %{list}" % {:list => list.join('. ')}
end

def valid_cluster?(vm)
transformation_mapping_items.where(:source => vm.ems_cluster).exists?
end

# return an empty array if all storages are valid for transformation
# otherwise return an array of invalid datastores
def unmapped_storages(vm)
vm.datastores - transformation_mapping_items.where(:source => vm.datastores).collect(&:source)
end

# return an empty array if all lans are valid for transformation
# otherwise return an array of invalid lans
def unmapped_lans(vm)
vm.lans - transformation_mapping_items.where(:source => vm.lans).collect(&:source)
def search_vms_and_validate(vm_list = nil)
VmMigrationValidator.new(self, vm_list).validate
end
end
144 changes: 144 additions & 0 deletions app/models/transformation_mapping/vm_migration_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
class TransformationMapping::VmMigrationValidator
require 'miq-hash_struct'

VM_CONFLICT = "conflict".freeze
VM_EMPTY_NAME = "empty_name".freeze
VM_IN_OTHER_PLAN = "in_other_plan".freeze
VM_INACTIVE = "inactive".freeze
VM_INVALID = "invalid".freeze
VM_MIGRATED = "migrated".freeze
VM_NOT_EXIST = "not_exist".freeze
VM_VALID = "ok".freeze

def initialize(mapping, vm_list = nil)
@mapping = mapping
@vm_list = vm_list
end

def validate
@vm_list.present? ? identify_vms : select_vms
end

def select_vms
valid_list = []

Vm.where(:ems_cluster => mapped_clusters).includes(:lans, :storages).each do |vm|
reason = validate_vm(vm, true)
valid_list << VmMigrateStruct.new(vm.name, vm, VM_VALID, reason) if reason == VM_VALID
end

{"valid" => valid_list}
end

def identify_vms
valid_list = []
invalid_list = []
conflict_list = []

vm_names = @vm_list.collect { |row| row['name'] }
vm_objects = Vm.where(:name => vm_names, :ems_cluster => mapped_clusters).includes(:lans, :storages, :host, :ext_management_system)

@vm_list.each do |row|
vm_name = row['name']

if vm_name.blank?
invalid_list << VmMigrateStruct.new('', nil, VM_INVALID, VM_EMPTY_NAME)
next
end

vms = vm_objects.select { |vm| vm.name == vm_name }
vms = vms.select { |vm| vm.uid_ems == row['uid_ems'] } if row['uid_ems'].present?
vms = vms.select { |vm| vm.host.name == row['host'] } if row['host'].present?
vms = vms.select { |vm| vm.ext_management_system.name == row['provider'] } if row['provider'].present?

if vms.empty?
invalid_list << VmMigrateStruct.new(vm_name, nil, VM_INVALID, VM_NOT_EXIST)
elsif vms.size == 1
vm = vms.first
reason = validate_vm(vm, false)
if reason == VM_VALID
valid_list << VmMigrateStruct.new(vm.name, vm, VM_VALID, reason)
else
invalid_list << VmMigrateStruct.new(vm.name, vm, VM_INVALID, reason)
end
else
vms.each { |v| conflict_list << VmMigrateStruct.new(v.name, v, VM_CONFLICT, VM_CONFLICT) }
end
end

{
"valid" => valid_list,
"invalid" => invalid_list,
"conflicted" => conflict_list
}
end

def validate_vm(vm, quick = true)
validate_result = vm_migration_status(vm)
return validate_result unless validate_result == VM_VALID

# a valid vm must find all resources in the mapping and has never been migrated
invalid_list = []

invalid_storages = vm.datastores - mapped_storages
if invalid_storages.present?
invalid_list << "storages: %{list}" % {:list => invalid_storages.collect(&:name).join(", ")}
return no_mapping_msg(invalid_list) if quick
end

invalid_lans = vm.lans - mapped_lans
if invalid_lans.present?
invalid_list << "lans: %{list}" % {:list => invalid_lans.collect(&:name).join(', ')}
return no_mapping_msg(invalid_list) if quick
end

invalid_list.present? ? no_mapping_msg(invalid_list) : VM_VALID
end

def vm_migration_status(vm)
return VM_INACTIVE unless vm.active?

vm_as_resources = ServiceResource.joins(:service_template).where(:resource => vm, :service_templates => {:type => 'ServiceTemplateTransformationPlan'})

# VM has not been migrated before
return VM_VALID if vm_as_resources.empty?

return VM_MIGRATED unless vm_as_resources.where(:status => ServiceResource::STATUS_COMPLETED).empty?

# VM failed in previous migration
vm_as_resources.all? { |rsc| rsc.status == ServiceResource::STATUS_FAILED } ? VM_VALID : VM_IN_OTHER_PLAN
end

def no_mapping_msg(list)
"Mapping source not found - %{list}" % {:list => list.join('. ')}
end

def mapped_clusters
@mapped_clusters ||= EmsCluster.where(:id => @mapping.transformation_mapping_items.where(:source_type => 'EmsCluster').select(:source_id))
end

def mapped_storages
@mapped_storages ||= Storage.where(:id => @mapping.transformation_mapping_items.where(:source_type => 'Storage').select(:source_id))
end

def mapped_lans
@mapped_lans ||= Lan.where(:id => @mapping.transformation_mapping_items.where(:source_type => 'Lan').select(:source_id))
end

class VmMigrateStruct < MiqHashStruct
def initialize(vm_name, vm, status, reason)
options = {"name" => vm_name, "status" => status, "reason" => reason}

if vm.present?
options.merge!(
"cluster" => vm.ems_cluster.try(:name) || '',
"path" => vm.ext_management_system ? "#{vm.ext_management_system.name}/#{vm.v_parent_blue_folder_display_path}" : '',
"allocated_size" => vm.allocated_disk_storage,
"id" => vm.id.to_s
)
end

super(options)
end
end
end
14 changes: 0 additions & 14 deletions app/models/vm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,20 +122,6 @@ def supported_consoles
}
end

def validate_v2v_migration
return TransformationMapping::VM_INACTIVE unless active?

vm_as_resources = ServiceResource.where(:resource => self).includes(:service_template).where(:service_templates => {:type => "ServiceTemplateTransformationPlan"})

# VM has not been migrated before
return TransformationMapping::VM_VALID if vm_as_resources.blank?

return TransformationMapping::VM_MIGRATED if vm_as_resources.any? { |rsc| rsc.status == ServiceResource::STATUS_COMPLETED }

# VM failed in previous migration
vm_as_resources.all? { |rsc| rsc.status == ServiceResource::STATUS_FAILED } ? TransformationMapping::VM_VALID : TransformationMapping::VM_IN_OTHER_PLAN
end

def self.display_name(number = 1)
n_('VM and Instance', 'VMs and Instances', number)
end
Expand Down
Loading

0 comments on commit 6d77f74

Please sign in to comment.