From 8a918cb33a402937612a0e8758e76e77719e7d36 Mon Sep 17 00:00:00 2001 From: Fabien Dupont Date: Fri, 28 Sep 2018 09:27:24 -0400 Subject: [PATCH] Add methods to conversion_host to build virt-v2v wrapper options --- app/models/conversion_host.rb | 101 ++++++ ...rvice_template_transformation_plan_task.rb | 67 +++- spec/models/conversion_host_spec.rb | 288 ++++++++++++++++++ ..._template_transformation_plan_task_spec.rb | 145 ++++++++- 4 files changed, 589 insertions(+), 12 deletions(-) create mode 100644 spec/models/conversion_host_spec.rb diff --git a/app/models/conversion_host.rb b/app/models/conversion_host.rb index 493569ff8047..b856c1011748 100644 --- a/app/models/conversion_host.rb +++ b/app/models/conversion_host.rb @@ -4,4 +4,105 @@ class ConversionHost < ApplicationRecord acts_as_miq_taggable belongs_to :resource, :polymorphic => true + + def active_tasks + ServiceTemplateTransformationPlanTask.where(:state => 'active').select do |task| + task.conversion_host == self + end + end + + def eligible? + return true if concurrent_transformation_limit.nil? + active_tasks.size < concurrent_transformation_limit.to_i + end + + def source_transport_method + return 'vddk' if vddk_transport_supported + return 'ssh' if ssh_transport_supported + end + + def conversion_options(task) + source_vm = task.source + source_ems = source_vm.ext_management_system + source_cluster = source_vm.ems_cluster + source_storage = source_vm.hardware.disks.select { |d| d.device_type == 'disk' }.first.storage + + destination_cluster = task.transformation_destination(source_cluster) + destination_storage = task.transformation_destination(source_storage) + destination_ems = destination_cluster.ext_management_system + + source_provider_options = send( + "conversion_options_source_provider_#{source_ems.emstype}_#{source_transport_method}", + source_vm, + source_storage + ) + destination_provider_options = send( + "conversion_options_destination_provider_#{destination_ems.emstype}", + task, + destination_ems, + destination_cluster, + destination_storage + ) + options = { + :source_disks => task.source_disks.map { |disk| disk[:path] }, + :network_mappings => task.network_mappings + } + options.merge(source_provider_options).merge(destination_provider_options) + end + + def conversion_options_source_provider_vmwarews_vddk(vm, _storage) + { + :vm_name => vm.name, + :transport_method => 'vddk', + :vmware_fingerprint => vm.host.fingerprint, + :vmware_uri => URI::Generic.build( + :scheme => 'esx', + :userinfo => CGI.escape(vm.host.authentication_userid), + :host => vm.host.ipaddress, + :path => '/', + :query => { :no_verify => 1 }.to_query + ).to_s, + :vmware_password => vm.host.authentication_password + } + end + + def conversion_options_source_provider_vmwarews_ssh(vm, storage) + { + :vm_name => URI::Generic.build(:scheme => 'ssh', :userinfo => 'root', :host => vm.host.ipaddress, :path => "/vmfs/volumes").to_s + "/#{storage.name}/#{vm.location}", + :transport_method => 'ssh' + } + end + + def conversion_options_destination_provider_rhevm(_task, ems, cluster, storage) + { + :rhv_url => URI::Generic.build(:scheme => 'https', :host => ems.hostname, :path => '/ovirt-engine/api').to_s, + :rhv_cluster => cluster.name, + :rhv_storage => storage.name, + :rhv_password => ems.authentication_password, + :install_drivers => true, + :insecure_connection => true + } + end + + def conversion_options_destination_provider_openstack(task, ems, cluster, storage) + { + :osp_environment => { + :os_no_cache => true, + :os_auth_url => URI::Generic.build( + :scheme => ems.security_protocol == 'non-ssl' ? 'http' : 'https', + :host => ems.hostname, + :port => ems.port, + :path => ems.api_version + ), + :os_user_domain_name => ems.uid_ems, + :os_username => ems.authentication_userid, + :os_password => ems.authentication_password, + :os_project_name => cluster.name + }, + :osp_destination_project_id => cluster.ems_ref, + :osp_volume_type_id => storage.ems_ref, + :osp_flavor_id => task.destination_flavor.ems_ref, + :osp_security_groups_ids => [task.destination_security_group.ems_ref] + } + end end diff --git a/app/models/service_template_transformation_plan_task.rb b/app/models/service_template_transformation_plan_task.rb index 000ba171a933..28a105c2ff4d 100644 --- a/app/models/service_template_transformation_plan_task.rb +++ b/app/models/service_template_transformation_plan_task.rb @@ -47,7 +47,64 @@ def task_active end def conversion_host - Host.find_by(:id => options[:transformation_host_id]) + ConversionHost.find_by(:id => options[:transformation_host_id]) + end + + def source_ems + options[:source_ems_id] ||= source.ext_management_system.id + source.ext_management_system + end + + def destination_ems + options[:destination_ems_id] ||= transformation_destination(source.ems_cluster).ext_management_system.id + transformation_destination(source.ems_cluster).ext_management_system + end + + def source_disks + options[:source_disks] ||= source.hardware.disks.select { |d| d.device_type == 'disk' }.collect do |disk| + source_storage = disk.storage + destination_storage = transformation_destination(disk.storage) + raise "[#{source.name}] Disk #{disk.device_name} [#{source_storage.name}] has no mapping. Aborting." if destination_storage.nil? + { + :path => disk.filename, + :size => disk.size, + :percent => 0, + :weight => disk.size.to_f / source.allocated_disk_storage.to_f * 100 + } + end + end + + def network_mappings + options[:network_mappings] ||= source.hardware.nics.select { |n| n.device_type == 'ethernet' }.collect do |nic| + source_network = nic.lan + destination_network = transformation_destination(source_network) + raise "[#{source.name}] NIC #{nic.device_name} [#{source_network.name}] has no mapping. Aborting." if destination_network.nil? + { + :source => source_network.name, + :destination => destination_network_ref(destination_network), + :mac_address => nic.address + } + end + end + + def destination_network_ref(network) + send("destination_network_ref_#{destination_ems.emstype}", network) + end + + def destination_network_ref_rhevm(network) + network.name + end + + def destination_network_ref_openstack(network) + network.ems_ref + end + + def destination_flavor + Flavor.find_by(:id => miq_request.source.options[:config_info][:osp_flavor]) + end + + def destination_security_group + SecurityGroup.find_by(:id => miq_request.source.options[:config_info][:osp_security_group]) end def transformation_log @@ -58,9 +115,9 @@ def transformation_log raise MiqException::Error, msg end - userid, password = host.auth_user_pwd(:remote) + userid, password = host.resource.auth_user_pwd(:remote) if userid.blank? || password.blank? - msg = "Credential was not found for host #{host.name}. Download of transformation log aborted." + msg = "Credential was not found for host #{host.resource.name}. Download of transformation log aborted." _log.error(msg) raise MiqException::Error, msg end @@ -74,7 +131,7 @@ def transformation_log begin require 'net/scp' - Net::SCP.download!(host.ipaddress, userid, logfile, nil, :ssh => {:password => password}) + Net::SCP.download!(host.resource.ipaddress, userid, logfile, nil, :ssh => {:password => password}) rescue Net::SCP::Error => scp_err _log.error("Download of transformation log for #{description} with ID [#{id}] failed with error: #{scp_err.message}") raise scp_err @@ -98,7 +155,7 @@ def transformation_log_queue(userid = nil) :instance_id => id, :priority => MiqQueue::HIGH_PRIORITY, :args => [], - :zone => host.my_zone} + :zone => host.resource.my_zone} MiqTask.generic_action_with_callback(options, queue_options) end diff --git a/spec/models/conversion_host_spec.rb b/spec/models/conversion_host_spec.rb new file mode 100644 index 000000000000..7c5a00a063ee --- /dev/null +++ b/spec/models/conversion_host_spec.rb @@ -0,0 +1,288 @@ +describe ConversionHost do + let(:apst) { FactoryGirl.create(:service_template_ansible_playbook) } + let(:conversion_host) { FactoryGirl.create(:conversion_host) } + + context "provider independent methods" do + let(:task_1) { FactoryGirl.create(:service_template_transformation_plan_task) } + let(:task_2) { FactoryGirl.create(:service_template_transformation_plan_task) } + let(:task_3) { FactoryGirl.create(:service_template_transformation_plan_task) } + + let(:conversion_host_1) { FactoryGirl.create(:conversion_host) } + let(:conversion_host_2) { FactoryGirl.create(:conversion_host) } + + before do + conversion_host_1.concurrent_transformation_limit = "2" + conversion_host_2.concurrent_transformation_limit = "1" + + task_1.options[:transformation_host_id] = conversion_host_1.id + task_2.options[:transformation_host_id] = conversion_host_1.id + task_3.options[:transformation_host_id] = conversion_host_2.id + + allow(ServiceTemplateTransformationPlanTask).to receive(:where).with(:state => 'active').and_return([task_1, task_3]) + end + + it "#active_tasks" do + expect(conversion_host_1.active_tasks).to eq([task_1]) + expect(conversion_host_2.active_tasks).to eq([task_3]) + end + + it "#eligible?" do + expect(conversion_host_1.eligible?).to eq(true) + expect(conversion_host_2.eligible?).to eq(false) + end + + context "#source_transport_method" do + it { expect(conversion_host_2.source_transport_method).to be_nil } + + context "ssh transport enabled" do + before { conversion_host_2.ssh_transport_supported = true } + it { expect(conversion_host_2.source_transport_method).to eq('ssh') } + + context "vddk transport enabled" do + before { conversion_host_2.vddk_transport_supported = true } + it { expect(conversion_host_2.source_transport_method).to eq('vddk') } + end + end + end + end + + context "source is vmwarews" do + let(:src_ems) { FactoryGirl.create(:ems_vmware, :zone => FactoryGirl.create(:zone)) } + let(:src_cluster) { FactoryGirl.create(:ems_cluster, :ext_management_system => src_ems) } + let(:src_host) { FactoryGirl.create(:host, :ext_management_system => src_ems, :ipaddress => '10.0.0.1') } + let(:src_storage) { FactoryGirl.create(:storage, :ext_management_system => src_ems) } + + let(:src_lan_1) { FactoryGirl.create(:lan) } + let(:src_lan_2) { FactoryGirl.create(:lan) } + let(:src_nic_1) { FactoryGirl.create(:guest_device_nic, :lan => src_lan_1) } + let(:src_nic_2) { FactoryGirl.create(:guest_device_nic, :lan => src_lan_2) } + + let(:src_disk_1) { instance_double("disk", :device_name => "Hard disk 1", :device_type => "disk", :filename => "[datastore12] test_vm/test_vm.vmdk", :size => 17_179_869_184) } + let(:src_disk_2) { instance_double("disk", :device_name => "Hard disk 2", :device_type => "disk", :filename => "[datastore12] test_vm/test_vm-2.vmdk", :size => 17_179_869_184) } + + let(:src_hardware) { FactoryGirl.create(:hardware, :nics => [src_nic_1, src_nic_2]) } + + let(:src_vm) { FactoryGirl.create(:vm_vmware, :ext_management_system => src_ems, :ems_cluster => src_cluster, :host => src_host, :hardware => src_hardware) } + + let(:source_disks) do + [ + {:path => src_disk_1.filename, :size => src_disk_1.size, :percent => 0, :weight => 50.0 }, + {:path => src_disk_2.filename, :size => src_disk_2.size, :percent => 0, :weight => 50.0 } + ] + end + + before do + allow(src_hardware).to receive(:disks).and_return([src_disk_1, src_disk_2]) + allow(src_disk_1).to receive(:storage).and_return(src_storage) + allow(src_host).to receive(:fingerprint).and_return('01:23:45:67:89:ab:cd:ef:01:23:45:67:89:ab:cd:ef:01:23:45:67') + allow(src_host).to receive(:authentication_userid).and_return('esx_user') + allow(src_host).to receive(:authentication_password).and_return('esx_passwd') + end + + context "destination is rhevm" do + let(:dst_ems) { FactoryGirl.create(:ems_redhat, :zone => FactoryGirl.create(:zone)) } + let(:dst_cluster) { FactoryGirl.create(:ems_cluster, :ext_management_system => dst_ems) } + let(:dst_storage) { FactoryGirl.create(:storage) } + let(:dst_lan_1) { FactoryGirl.create(:lan) } + let(:dst_lan_2) { FactoryGirl.create(:lan) } + + let(:mapping) do + FactoryGirl.create( + :transformation_mapping, + :transformation_mapping_items => [ + TransformationMappingItem.new(:source => src_cluster, :destination => dst_cluster), + TransformationMappingItem.new(:source => src_storage, :destination => dst_storage), + TransformationMappingItem.new(:source => src_lan_1, :destination => dst_lan_1), + TransformationMappingItem.new(:source => src_lan_2, :destination => dst_lan_2) + ] + ) + end + + let(:catalog_item_options) do + { + :name => 'Transformation Plan', + :description => 'a description', + :config_info => { + :transformation_mapping_id => mapping.id, + :pre_service_id => apst.id, + :post_service_id => apst.id, + :actions => [ + {:vm_id => src_vm.id.to_s, :pre_service => true, :post_service => true} + ], + } + } + end + + let(:plan) { ServiceTemplateTransformationPlan.create_catalog_item(catalog_item_options) } + let(:request) { FactoryGirl.create(:service_template_transformation_plan_request, :source => plan) } + let(:task) { FactoryGirl.create(:service_template_transformation_plan_task, :miq_request => request, :request_type => 'transformation_plan', :source => src_vm) } + + before do + task.options[:transformation_host_id] = conversion_host.id + allow(task).to receive(:source_disks).and_return(source_disks) + end + + context "transport method is vddk" do + before do + conversion_host.vddk_transport_supported = true + end + + it "#conversion_options" do + expect(conversion_host.conversion_options(task)).to eq( + :vm_name => src_vm.name, + :transport_method => 'vddk', + :vmware_fingerprint => '01:23:45:67:89:ab:cd:ef:01:23:45:67:89:ab:cd:ef:01:23:45:67', + :vmware_uri => "esx://esx_user@10.0.0.1/?no_verify=1", + :vmware_password => 'esx_passwd', + :rhv_url => "https://#{dst_ems.hostname}/ovirt-engine/api", + :rhv_cluster => dst_cluster.name, + :rhv_storage => dst_storage.name, + :rhv_password => dst_ems.authentication_password, + :source_disks => [src_disk_1.filename, src_disk_2.filename], + :network_mappings => task.network_mappings, + :install_drivers => true, + :insecure_connection => true + ) + end + end + + context "transport method is ssh" do + before do + conversion_host.vddk_transport_supported = false + conversion_host.ssh_transport_supported = true + end + + it "#conversion_options" do + expect(conversion_host.conversion_options(task)).to eq( + :vm_name => "ssh://root@10.0.0.1/vmfs/volumes/#{src_storage.name}/#{src_vm.location}", + :transport_method => 'ssh', + :rhv_url => "https://#{dst_ems.hostname}/ovirt-engine/api", + :rhv_cluster => dst_cluster.name, + :rhv_storage => dst_storage.name, + :rhv_password => dst_ems.authentication_password, + :source_disks => [src_disk_1.filename, src_disk_2.filename], + :network_mappings => task.network_mappings, + :install_drivers => true, + :insecure_connection => true + ) + end + end + end + + context "destination is openstack" do + let(:dst_ems) { FactoryGirl.create(:ems_openstack, :zone => FactoryGirl.create(:zone)) } + let(:dst_cloud_tenant) { FactoryGirl.create(:cloud_tenant, :ext_management_system => dst_ems) } + let(:dst_cloud_volume_type) { FactoryGirl.create(:cloud_volume_type) } + let(:dst_cloud_network_1) { FactoryGirl.create(:cloud_network) } + let(:dst_cloud_network_2) { FactoryGirl.create(:cloud_network) } + let(:dst_flavor) { FactoryGirl.create(:flavor) } + let(:dst_security_group) { FactoryGirl.create(:security_group) } + + let(:mapping) do + FactoryGirl.create( + :transformation_mapping, + :transformation_mapping_items => [ + TransformationMappingItem.new(:source => src_cluster, :destination => dst_cloud_tenant), + TransformationMappingItem.new(:source => src_storage, :destination => dst_cloud_volume_type), + TransformationMappingItem.new(:source => src_lan_1, :destination => dst_cloud_network_1), + TransformationMappingItem.new(:source => src_lan_2, :destination => dst_cloud_network_2) + ] + ) + end + + let(:catalog_item_options) do + { + :name => 'Transformation Plan', + :description => 'a description', + :config_info => { + :transformation_mapping_id => mapping.id, + :pre_service_id => apst.id, + :post_service_id => apst.id, + :osp_flavor => dst_flavor.id, + :osp_security_group => dst_security_group.id, + :actions => [ + {:vm_id => src_vm.id.to_s, :pre_service => true, :post_service => true} + ], + } + } + end + + let(:plan) { ServiceTemplateTransformationPlan.create_catalog_item(catalog_item_options) } + let(:request) { FactoryGirl.create(:service_template_transformation_plan_request, :source => plan) } + let(:task) { FactoryGirl.create(:service_template_transformation_plan_task, :miq_request => request, :request_type => 'transformation_plan', :source => src_vm) } + + before do + task.options[:transformation_host_id] = conversion_host.id + allow(task).to receive(:source_disks).and_return(source_disks) + end + + context "transport method is vddk" do + before do + conversion_host.vddk_transport_supported = true + end + + it "#conversion_options" do + expect(conversion_host.conversion_options(task)).to eq( + :vm_name => src_vm.name, + :transport_method => 'vddk', + :vmware_fingerprint => '01:23:45:67:89:ab:cd:ef:01:23:45:67:89:ab:cd:ef:01:23:45:67', + :vmware_uri => "esx://esx_user@10.0.0.1/?no_verify=1", + :vmware_password => 'esx_passwd', + :osp_environment => { + :os_no_cache => true, + :os_auth_url => URI::Generic.build( + :scheme => dst_ems.security_protocol == 'non-ssl' ? 'http' : 'https', + :host => dst_ems.hostname, + :port => dst_ems.port, + :path => dst_ems.api_version + ), + :os_user_domain_name => dst_ems.uid_ems, + :os_username => dst_ems.authentication_userid, + :os_password => dst_ems.authentication_password, + :os_project_name => dst_cloud_tenant.name + }, + :osp_destination_project_id => dst_cloud_tenant.ems_ref, + :osp_volume_type_id => dst_cloud_volume_type.ems_ref, + :osp_flavor_id => dst_flavor.ems_ref, + :osp_security_groups_ids => [dst_security_group.ems_ref], + :source_disks => [src_disk_1.filename, src_disk_2.filename], + :network_mappings => task.network_mappings + ) + end + end + + context "transport method is ssh" do + before do + conversion_host.vddk_transport_supported = false + conversion_host.ssh_transport_supported = true + end + + it "#conversion_options" do + expect(conversion_host.conversion_options(task)).to eq( + :vm_name => "ssh://root@10.0.0.1/vmfs/volumes/#{src_storage.name}/#{src_vm.location}", + :transport_method => 'ssh', + :osp_environment => { + :os_no_cache => true, + :os_auth_url => URI::Generic.build( + :scheme => dst_ems.security_protocol == 'non-ssl' ? 'http' : 'https', + :host => dst_ems.hostname, + :port => dst_ems.port, + :path => dst_ems.api_version + ), + :os_user_domain_name => dst_ems.uid_ems, + :os_username => dst_ems.authentication_userid, + :os_password => dst_ems.authentication_password, + :os_project_name => dst_cloud_tenant.name + }, + :osp_destination_project_id => dst_cloud_tenant.ems_ref, + :osp_volume_type_id => dst_cloud_volume_type.ems_ref, + :osp_flavor_id => dst_flavor.ems_ref, + :osp_security_groups_ids => [dst_security_group.ems_ref], + :source_disks => [src_disk_1.filename, src_disk_2.filename], + :network_mappings => task.network_mappings + ) + end + end + end + end +end diff --git a/spec/models/service_template_transformation_plan_task_spec.rb b/spec/models/service_template_transformation_plan_task_spec.rb index f379db74cfb3..42913ff27112 100644 --- a/spec/models/service_template_transformation_plan_task_spec.rb +++ b/spec/models/service_template_transformation_plan_task_spec.rb @@ -12,9 +12,10 @@ end end - context 'populated request and task' do + context 'independent of provider' do let(:src) { FactoryGirl.create(:ems_cluster) } let(:dst) { FactoryGirl.create(:ems_cluster) } + let(:host) { FactoryGirl.create(:host, :ext_management_system => FactoryGirl.create(:ext_management_system, :zone => FactoryGirl.create(:zone))) } let(:vm) { FactoryGirl.create(:vm_or_template) } let(:vm2) { FactoryGirl.create(:vm_or_template) } let(:apst) { FactoryGirl.create(:service_template_ansible_playbook) } @@ -102,16 +103,16 @@ end describe '#transformation_log_queue' do - let(:host_id) { 22 } + let(:conversion_host_id) { 22 } before do - task.options[:transformation_host_id] = host_id + task.options[:transformation_host_id] = conversion_host_id task.save! end context 'when conversion host exists' do before do - FactoryGirl.create(:host, :id => host_id, :ext_management_system => FactoryGirl.create(:ext_management_system, :zone => FactoryGirl.create(:zone))) + FactoryGirl.create(:conversion_host, :id => conversion_host_id, :resource => host) allow(described_class).to receive(:find).and_return(task) @@ -146,7 +147,7 @@ it 'returns an error message' do taskid = task.transformation_log_queue('user') expect(MiqTask.find(taskid)).to have_attributes( - :message => "Conversion host was not found: ID [#{host_id}]. Cannot queue the download of transformation log.", + :message => "Conversion host was not found: ID [#{conversion_host_id}]. Cannot queue the download of transformation log.", :status => 'Error' ) end @@ -154,11 +155,11 @@ end describe '#transformation_log' do - let(:host) { FactoryGirl.create(:host, :id => 9) } + let(:conversion_host) { FactoryGirl.create(:conversion_host, :id => 9, :resource => host) } before do EvmSpecHelper.create_guid_miq_server_zone - task.options[:transformation_host_id] = host.id + task.options[:transformation_host_id] = conversion_host.id task.options.store_path(:virtv2v_wrapper, "v2v_log", "/path/to/log.file") task.save! @@ -205,4 +206,134 @@ end end end + + context 'populated request and task' do + let(:src_ems) { FactoryGirl.create(:ext_management_system, :zone => FactoryGirl.create(:zone)) } + let(:src_cluster) { FactoryGirl.create(:ems_cluster, :ext_management_system => src_ems) } + let(:dst_ems) { FactoryGirl.create(:ext_management_system, :zone => FactoryGirl.create(:zone)) } + let(:dst_cluster) { FactoryGirl.create(:ems_cluster, :ext_management_system => dst_ems) } + + let(:src_vm_1) { FactoryGirl.create(:vm_or_template, :ext_management_system => src_ems, :ems_cluster => src_cluster) } + let(:src_vm_2) { FactoryGirl.create(:vm_or_template, :ext_management_system => src_ems, :ems_cluster => src_cluster) } + let(:apst) { FactoryGirl.create(:service_template_ansible_playbook) } + + let(:mapping) do + FactoryGirl.create( + :transformation_mapping, + :transformation_mapping_items => [TransformationMappingItem.new(:source => src_cluster, :destination => dst_cluster)] + ) + end + + let(:catalog_item_options) do + { + :name => 'Transformation Plan', + :description => 'a description', + :config_info => { + :transformation_mapping_id => mapping.id, + :pre_service_id => apst.id, + :post_service_id => apst.id, + :actions => [ + {:vm_id => src_vm_1.id.to_s, :pre_service => true, :post_service => true}, + {:vm_id => src_vm_2.id.to_s, :pre_service => false, :post_service => false}, + ], + } + } + end + + let(:plan) { ServiceTemplateTransformationPlan.create_catalog_item(catalog_item_options) } + let(:request) { FactoryGirl.create(:service_template_transformation_plan_request, :source => plan) } + let(:task_1) { FactoryGirl.create(:service_template_transformation_plan_task, :miq_request => request, :request_type => 'transformation_plan', :source => src_vm_1) } + let(:task_2) { FactoryGirl.create(:service_template_transformation_plan_task, :miq_request => request, :request_type => 'transformation_plan', :source => src_vm_2) } + + describe '#transformation_destination' do + it { expect(task_1.transformation_destination(src_cluster)).to eq(dst_cluster) } + end + + describe '#pre_ansible_playbook_service_template' do + it { expect(task_1.pre_ansible_playbook_service_template).to eq(apst) } + it { expect(task_2.pre_ansible_playbook_service_template).to be_nil } + end + + describe '#post_ansible_playbook_service_template' do + it { expect(task_1.post_ansible_playbook_service_template).to eq(apst) } + it { expect(task_2.post_ansible_playbook_service_template).to be_nil } + end + + context 'source is vmwarews' do + let(:src_ems) { FactoryGirl.create(:ems_vmware, :zone => FactoryGirl.create(:zone)) } + let(:src_host) { FactoryGirl.create(:host, :ext_management_system => src_ems) } + let(:src_storage) { FactoryGirl.create(:storage, :ext_management_system => src_ems) } + + let(:src_lan_1) { FactoryGirl.create(:lan) } + let(:src_lan_2) { FactoryGirl.create(:lan) } + let(:src_nic_1) { FactoryGirl.create(:guest_device_nic, :lan => src_lan_1) } + let(:src_nic_2) { FactoryGirl.create(:guest_device_nic, :lan => src_lan_2) } + + let(:src_disk_1) { instance_double("disk", :device_name => "Hard disk 1", :device_type => "disk", :filename => "[datastore12] test_vm/test_vm.vmdk", :size => 17_179_869_184) } + let(:src_disk_2) { instance_double("disk", :device_name => "Hard disk 2", :device_type => "disk", :filename => "[datastore12] test_vm/test_vm-2.vmdk", :size => 17_179_869_184) } + + let(:src_hardware) { FactoryGirl.create(:hardware, :nics => [src_nic_1, src_nic_2]) } + + let(:src_vm_1) { FactoryGirl.create(:vm_vmware, :ext_management_system => src_ems, :ems_cluster => src_cluster, :host => src_host, :hardware => src_hardware) } + let(:src_vm_2) { FactoryGirl.create(:vm_vmware, :ext_management_system => src_ems, :ems_cluster => src_cluster, :host => src_host) } + + let(:conversion_host) { FactoryGirl.create(:conversion_host) } + + # Disks have to be stubbed because there's no factory for Disk class + before do + allow(src_hardware).to receive(:disks).and_return([src_disk_1, src_disk_2]) + allow(src_disk_1).to receive(:storage).and_return(src_storage) + allow(src_disk_2).to receive(:storage).and_return(src_storage) + allow(src_vm_1).to receive(:allocated_disk_storage).and_return(34_359_738_368) + task_1.options[:transformation_host_id] = conversion_host.id + end + + it "has source_ems" do + expect(task_1.source_ems).to eq(src_ems) + expect(task_1.options[:source_ems_id]).to eq(src_ems.id) + end + + it 'has destination_ems' do + expect(task_1.destination_ems).to eq(dst_ems) + expect(task_1.options[:destination_ems_id]).to eq(dst_ems.id) + end + + context 'destination is rhevm' do + let(:dst_ems) { FactoryGirl.create(:ems_redhat, :zone => FactoryGirl.create(:zone)) } + let(:dst_storage) { FactoryGirl.create(:storage) } + let(:dst_lan_1) { FactoryGirl.create(:lan) } + let(:dst_lan_2) { FactoryGirl.create(:lan) } + + let(:mapping) do + FactoryGirl.create( + :transformation_mapping, + :transformation_mapping_items => [ + TransformationMappingItem.new(:source => src_cluster, :destination => dst_cluster), + TransformationMappingItem.new(:source => src_storage, :destination => dst_storage), + TransformationMappingItem.new(:source => src_lan_1, :destination => dst_lan_1), + TransformationMappingItem.new(:source => src_lan_2, :destination => dst_lan_2) + ] + ) + end + + it "has source_disks" do + expect(task_1.source_disks).to eq( + [ + { :path => src_disk_1.filename, :size => src_disk_1.size, :percent => 0, :weight => 50.0 }, + { :path => src_disk_2.filename, :size => src_disk_2.size, :percent => 0, :weight => 50.0 } + ] + ) + end + + it "has network_mappings" do + expect(task_1.network_mappings).to eq( + [ + { :source => src_lan_1.name, :destination => dst_lan_1.name, :mac_address => src_nic_1.address }, + { :source => src_lan_2.name, :destination => dst_lan_2.name, :mac_address => src_nic_2.address } + ] + ) + end + end + end + end end