diff --git a/app/models/manageiq/providers/redhat/infra_manager.rb b/app/models/manageiq/providers/redhat/infra_manager.rb index 108c69e673c..412c1a09be5 100644 --- a/app/models/manageiq/providers/redhat/infra_manager.rb +++ b/app/models/manageiq/providers/redhat/infra_manager.rb @@ -133,4 +133,22 @@ def remove_disks(disks, vm) disks.each { |disk_id| service.attachment_service(disk_id).remove } end end + + def vm_migrate(vm, options = {}) + host_id = URI(options[:host]).path.split('/').last + + migration_options = { + :host => { + :id => host_id + } + } + + with_version4_vm_service(vm) do |service| + service.migrate(migration_options) + end + end + + def unsupported_migration_options + [:storage, :respool, :folder, :datacenter, :host_filter] + end end diff --git a/app/models/manageiq/providers/redhat/infra_manager/api_integration.rb b/app/models/manageiq/providers/redhat/infra_manager/api_integration.rb index 496b966e34d..bca8ea27881 100644 --- a/app/models/manageiq/providers/redhat/infra_manager/api_integration.rb +++ b/app/models/manageiq/providers/redhat/infra_manager/api_integration.rb @@ -198,8 +198,15 @@ def version_3_0? # Adding disks is supported only by API version 4.0 def with_disk_attachments_service(vm) + with_version4_vm_service(vm) do |service| + disk_service = service.disk_attachments_service + yield disk_service + end + end + + def with_version4_vm_service(vm) connection = connect(:version => 4) - service = connection.system_service.vms_service.vm_service(vm.uid_ems).disk_attachments_service + service = connection.system_service.vms_service.vm_service(vm.uid_ems) yield service ensure connection.close @@ -211,7 +218,7 @@ def api3_supported_features end def api4_supported_features - [:quick_stats, :snapshots] + [:quick_stats, :snapshots, :migrate] end def api_features diff --git a/app/models/manageiq/providers/redhat/infra_manager/vm.rb b/app/models/manageiq/providers/redhat/infra_manager/vm.rb index eb3151809b6..aa6ca3f922a 100644 --- a/app/models/manageiq/providers/redhat/infra_manager/vm.rb +++ b/app/models/manageiq/providers/redhat/infra_manager/vm.rb @@ -4,7 +4,11 @@ class ManageIQ::Providers::Redhat::InfraManager::Vm < ManageIQ::Providers::Infra include_concern 'Reconfigure' include_concern 'ManageIQ::Providers::Redhat::InfraManager::VmOrTemplateShared' - supports_not :migrate, :reason => _("Migrate operation is not supported.") + supports :migrate do + unless ext_management_system.supports_migrate? + unsupported_reason_add(:migrate, 'RHV API version does not support migrate') + end + end POWER_STATES = { 'up' => 'on', diff --git a/app/models/vm_migrate_workflow.rb b/app/models/vm_migrate_workflow.rb index 840c1254f34..5fd8532d238 100644 --- a/app/models/vm_migrate_workflow.rb +++ b/app/models/vm_migrate_workflow.rb @@ -22,6 +22,8 @@ def get_source_and_targets(refresh = false) return @target_resource = {} if ems.length != 1 result = {:ems => ci_to_hash_struct(ems.first)} + @manager = ems.first + add_target(:placement_host_name, :host, Host, result) add_target(:placement_ds_name, :storage, Storage, result) add_target(:placement_cluster_name, :cluster, EmsCluster, result) @@ -38,6 +40,15 @@ def get_source_and_targets(refresh = false) @target_resource = result end + def add_target(dialog_key, key, klass, result) + super if field_supported(key) + end + + def field_supported(key) + !(@manager.respond_to?(:unsupported_migration_options) && + @manager.unsupported_migration_options.include?(key)) + end + private def allowed_ci(ci, relats, filtered_ids = nil) diff --git a/app/views/miq_request/_prov_vm_migrate_dialog.html.haml b/app/views/miq_request/_prov_vm_migrate_dialog.html.haml index a1168538bcb..d01c0d1adac 100644 --- a/app/views/miq_request/_prov_vm_migrate_dialog.html.haml +++ b/app/views/miq_request/_prov_vm_migrate_dialog.html.haml @@ -21,12 +21,13 @@ :label => _("Manager"), :keys => keys}) - when :environment - - keys = [:placement_dc_name] - = render(:partial => "/miq_request/prov_dialog_fieldset", - :locals => {:workflow => wf, - :dialog => dialog, - :label => _("Datacenter"), - :keys => keys}) + - if wf.field_supported(:datacenter) + - keys = [:placement_dc_name] + = render(:partial => "/miq_request/prov_dialog_fieldset", + :locals => {:workflow => wf, + :dialog => dialog, + :label => _("Datacenter"), + :keys => keys}) - keys = [:cluster_filter, :placement_cluster_name] = render(:partial => "/miq_request/prov_dialog_fieldset", @@ -35,14 +36,15 @@ :label => title_for_cluster, :keys => keys}) - - keys = [:rp_filter, :placement_rp_name] - = render(:partial => "/miq_request/prov_dialog_fieldset", - :locals => {:workflow => wf, - :dialog => dialog, - :label => _("Resource Pool"), - :keys => keys}) + - if wf.field_supported(:respool) + - keys = [:rp_filter, :placement_rp_name] + = render(:partial => "/miq_request/prov_dialog_fieldset", + :locals => {:workflow => wf, + :dialog => dialog, + :label => _("Resource Pool"), + :keys => keys}) - - keys = [:host_filter, :placement_host_name] + - keys = [wf.field_supported(:host_filter) ? :host_filter : nil, :placement_host_name].compact = render(:partial => "/miq_request/prov_dialog_fieldset", :locals => {:workflow => wf, :dialog => dialog, @@ -50,13 +52,15 @@ :keys => keys, :extra_table_attributes => "width=100%"}) - - keys = [:ds_filter, :placement_ds_name] - = render(:partial => "/miq_request/prov_dialog_fieldset", - :locals => {:workflow => wf, - :dialog => dialog, - :label => _("Datastore"), - :keys => keys, - :extra_table_attributes => "width=100%"}) + - if wf.field_supported(:storage) + - keys = [:ds_filter, :placement_ds_name] + = render(:partial => "/miq_request/prov_dialog_fieldset", + :locals => {:workflow => wf, + :dialog => dialog, + :label => _("Datastore"), + :keys => keys, + :extra_table_attributes => "width=100%"}) + - when :hardware - keys = [:disk_format] = render(:partial => "/miq_request/prov_dialog_fieldset", diff --git a/spec/models/vm_migrate_workflow_spec.rb b/spec/models/vm_migrate_workflow_spec.rb index d0a738cb542..ab4c6e9bb31 100644 --- a/spec/models/vm_migrate_workflow_spec.rb +++ b/spec/models/vm_migrate_workflow_spec.rb @@ -4,6 +4,9 @@ let(:ems) { FactoryGirl.create(:ems_vmware) } let(:vm) { FactoryGirl.create(:vm_vmware, :name => 'My VM', :ext_management_system => ems) } + let(:redhat_ems) { FactoryGirl.create(:ems_redhat) } + let(:redhat_vm) { FactoryGirl.create(:vm_redhat, :name => 'My RHV VM', :ext_management_system => redhat_ems) } + context "With a Valid Template," do context "#allowed_hosts" do let(:workflow) { VmMigrateWorkflow.new({:src_ids => [vm.id]}, admin) } @@ -26,6 +29,33 @@ end end + describe "Configuring targets" do + context "redhat VM" do + let(:workflow) { VmMigrateWorkflow.new({:src_ids => [redhat_vm.id]}, admin) } + + it "excludes some properties in" do + stub_dialog + workflow.get_source_and_targets + target_resource = workflow.instance_variable_get(:@target_resource) + expect(target_resource).not_to include(:storage_id, :respool_id, :folder_id, + :datacenter_id) + expect(target_resource).to include(:host_id, :cluster_id) + end + end + + context "vmware VM" do + let(:workflow) { VmMigrateWorkflow.new({:src_ids => [vm.id]}, admin) } + + it "includes all properties in" do + stub_dialog + workflow.get_source_and_targets + target_resource = workflow.instance_variable_get(:@target_resource) + expect(target_resource).to include(:host_id, :cluster_id, :storage_id, :respool_id, + :folder_id, :datacenter_id) + end + end + end + describe "#make_request" do let(:alt_user) { FactoryGirl.create(:user_with_group) }