diff --git a/app/models/transformation_mapping_item.rb b/app/models/transformation_mapping_item.rb index 6186119f673..8e57c5e7e98 100644 --- a/app/models/transformation_mapping_item.rb +++ b/app/models/transformation_mapping_item.rb @@ -3,25 +3,56 @@ class TransformationMappingItem < ApplicationRecord belongs_to :source, :polymorphic => true belongs_to :destination, :polymorphic => true - validates :source_id, :uniqueness => {:scope => [:transformation_mapping_id, :source_type]} + validates :source_id, :uniqueness => {:scope => [:transformation_mapping_id, :source_type, :destination_type]} - validate :source_cluster, :if => -> { source.kind_of?(EmsCluster) } - validate :destination_cluster, :if => -> { destination.kind_of?(EmsCluster) || destination.kind_of?(CloudTenant) } + validate :validate_source_cluster, :if => -> { source.kind_of?(EmsCluster) } + validate :validate_destination_cluster, :if => -> { destination.kind_of?(EmsCluster) || destination.kind_of?(CloudTenant) } + + validate :validate_source_datastore, :if => -> { source.kind_of?(Storage) } + validate :validate_destination_datastore, :if => -> { destination.kind_of?(Storage) || destination.kind_of?(CloudVolume) } VALID_SOURCE_CLUSTER_PROVIDERS = %w[vmwarews].freeze VALID_DESTINATION_CLUSTER_PROVIDERS = %w[rhevm openstack].freeze - def source_cluster + def validate_source_cluster unless VALID_SOURCE_CLUSTER_PROVIDERS.include?(source.ext_management_system.emstype) source_types = VALID_SOURCE_CLUSTER_PROVIDERS.join(', ') errors.add(:source, "EMS type of source cluster must be in: #{source_types}") end end - def destination_cluster + def validate_destination_cluster unless VALID_DESTINATION_CLUSTER_PROVIDERS.include?(destination.ext_management_system.emstype) destination_types = VALID_DESTINATION_CLUSTER_PROVIDERS.join(', ') errors.add(:destination, "EMS type of destination cluster or cloud tenant must be in: #{destination_types}") end end + + def validate_source_datastore + tm = transformation_mapping + tmis = tm.transformation_mapping_items.where(:source_type => "EmsCluster") + src_cluster_storages = tmis.collect(&:source).flat_map(&:storages) + source_storage = source + + unless src_cluster_storages.include?(source_storage) + errors.add(:source, "Source cluster storages must include source storage: #{source_storage}") + end + end + + def validate_destination_datastore + tm = transformation_mapping + destination_storage = destination + + if destination.kind_of?(Storage) # red hat + tmis = tm.transformation_mapping_items.where(:destination_type=> "EmsCluster") + dst_cluster_storages = tmis.collect(&:destination).flat_map(&:storages) + elsif destination.kind_of?(CloudVolume) # Openstack + tmis = tm.transformation_mapping_items.where(:destination_type => "CloudTenant") + dst_cluster_storages = tmis.collect(&:destination).flat_map(&:cloud_volumes) + end + + unless dst_cluster_storages.include?(destination_storage) + errors.add(:destination, "Destination cluster storages must include destination storage: #{destination_storage}") + end + end end diff --git a/spec/models/transformation_mapping_item_spec.rb b/spec/models/transformation_mapping_item_spec.rb index 8571dc8c022..a2df80dcac9 100644 --- a/spec/models/transformation_mapping_item_spec.rb +++ b/spec/models/transformation_mapping_item_spec.rb @@ -45,4 +45,59 @@ expect(invalid_mapping_item.errors[:destination].first).to match("EMS type of destination cluster or cloud tenant must be in") end end + + context "datastore validation" do + let(:ems_vmware) { FactoryBot.create(:ems_vmware) } + let(:vmware_cluster) { FactoryBot.create(:ems_cluster, :ext_management_system => ems_vmware) } + + let(:ems_redhat) { FactoryBot.create(:ems_redhat) } + let(:redhat_cluster) { FactoryBot.create(:ems_cluster, :ext_management_system => ems_redhat) } + + let(:ems_ops) { FactoryBot.create(:ems_openstack) } + let(:cloud_tenant) { FactoryBot.create(:cloud_tenant_openstack, :ext_management_system => ems_ops) } + + context "source vmware datastore" do + let(:src_vmware_host) { FactoryBot.create(:host_vmware, :ems_cluster => vmware_cluster) } + let(:src_storage) { FactoryBot.create(:storage_vmware, :hosts => [src_vmware_host]) } + + context "destination openstack" do + let(:disk) { FactoryBot.create(:disk) } + let(:cloud_volume_openstack) { FactoryBot.create(:cloud_volume_openstack, :attachments => [disk], :cloud_tenant => cloud_tenant) } + + let(:tmi_ops_cluster) { FactoryBot.create(:transformation_mapping_item, :source => vmware_cluster, :destination => cloud_tenant) } + let(:ops_mapping) { FactoryBot.create(:transformation_mapping, :transformation_mapping_items => [tmi_ops_cluster]) } + + let(:valid_source) { FactoryBot.create(:transformation_mapping_item, :source => src_storage, :destination => cloud_volume_openstack, :transformation_mapping_id => ops_mapping.id) } + let(:invalid_source) { FactoryBot.build(:transformation_mapping_item, :source => cloud_volume_openstack, :destination => src_storage, :transformation_mapping_id => ops_mapping.id) } + + it "valid source" do + expect(valid_source.valid?).to be(true) + end + it "invalid source" do + expect(invalid_source.valid?).to be(false) + end + end + + context "destination red hat" do + let(:dst_redhat_host) { FactoryBot.create(:host_redhat, :ems_cluster => redhat_cluster) } + let(:dst_storage) { FactoryBot.create(:storage_nfs, :hosts => [dst_redhat_host]) } + + let(:tmi_cluster) { FactoryBot.create(:transformation_mapping_item, :source => vmware_cluster, :destination => redhat_cluster) } + + let(:rh_mapping) { FactoryBot.create(:transformation_mapping, :transformation_mapping_items => [tmi_cluster]) } + + context "source validation" do + let(:valid_storage) { FactoryBot.create(:transformation_mapping_item, :source => src_storage, :destination => dst_storage, :transformation_mapping_id => rh_mapping.id) } + let(:invalid_storage) { FactoryBot.build(:transformation_mapping_item, :source => dst_storage, :destination => src_storage, :transformation_mapping_id => rh_mapping.id) } + + it "validate rhev destination" do + expect(valid_storage.valid?).to be(true) + end + it "invalidate badrhev destination" do + expect(invalid_storage.valid?).to be(false) + end + end + end + end + end end