diff --git a/app/controllers/api/cloud_volumes_controller.rb b/app/controllers/api/cloud_volumes_controller.rb index a1f61a3f4f..b42f0cae32 100644 --- a/app/controllers/api/cloud_volumes_controller.rb +++ b/app/controllers/api/cloud_volumes_controller.rb @@ -34,7 +34,8 @@ def delete_resource_main_action(_type, cloud_volume, _data) def options if (id = params["id"]) - render_update_resource_options(id) + action = params["option_action"] || "update" + send("render_#{action}_resource_options", id) elsif (ems_id = params["ems_id"]) render_create_resource_options(ems_id) else @@ -54,5 +55,27 @@ def restore_backup_resource(type, id, data) {:task_id => cloud_volume.backup_restore_queue(User.current_userid, backup['ems_ref'])} end end + + def attach_resource(type, id, data = {}) + api_resource(type, id, "Attaching Resource to", :supports => :attach_volume) do |cloud_volume| + raise BadRequestError, "Must specify a vm_id" if data["vm_id"].blank? + + vm = resource_search(data["vm_id"], :vms) + {:task_id => cloud_volume.attach_volume_queue(User.current_userid, vm.ems_ref, data["device"].presence)} + end + rescue => err + action_result(false, err.to_s) + end + + def detach_resource(type, id, data = {}) + api_resource(type, id, "Detaching Resource from", :supports => :detach_volume) do |cloud_volume| + raise BadRequestError, "Must specify a vm_id" if data["vm_id"].blank? + + vm = resource_search(data["vm_id"], :vms) + {:task_id => cloud_volume.detach_volume_queue(User.current_userid, vm.ems_ref)} + end + rescue => err + action_result(false, err.to_s) + end end end diff --git a/config/api.yml b/config/api.yml index 9c561b68a5..3dd84c2f5f 100644 --- a/config/api.yml +++ b/config/api.yml @@ -801,6 +801,10 @@ :identifier: cloud_volume_backup_create - :name: restore_backup :identifier: cloud_volume_backup_restore + - :name: attach + :identifier: cloud_volume_edit + - :name: detach + :identifier: cloud_volume_edit :tags_subcollection_actions: :post: - :name: assign diff --git a/spec/requests/cloud_volumes_spec.rb b/spec/requests/cloud_volumes_spec.rb index 87ae86b87f..b45b4a0fb4 100644 --- a/spec/requests/cloud_volumes_spec.rb +++ b/spec/requests/cloud_volumes_spec.rb @@ -208,6 +208,68 @@ expect(response).to have_http_status(:ok) end + + it 'attaches Cloud Volume to an instance' do + zone = FactoryBot.create(:zone) + ems = FactoryBot.create(:ems_autosde, :zone => zone) + vm = FactoryBot.create(:vm_vmware) + cloud_volume = FactoryBot.create(:cloud_volume_autosde, :ext_management_system => ems) + + api_basic_authorize(action_identifier(:cloud_volumes, :attach, :resource_actions, :post)) + stub_supports(cloud_volume.class, :attach_volume) + + payload = {:action => "attach", :resources => {:vm_id => vm.id.to_s}} + post(api_cloud_volume_url(nil, cloud_volume), :params => payload) + + expect(response).to have_http_status(:ok) + end + + it 'detaches Cloud Volume from an instance' do + zone = FactoryBot.create(:zone) + ems = FactoryBot.create(:ems_autosde, :zone => zone) + hw = FactoryBot.create(:hardware) + vm = FactoryBot.create(:vm_vmware, :hardware => hw) + cloud_volume = FactoryBot.create(:cloud_volume_autosde, :ext_management_system => ems) + FactoryBot.create(:disk, :hardware => hw, :backing => cloud_volume) + + api_basic_authorize(action_identifier(:cloud_volumes, :detach, :resource_actions, :post)) + stub_supports(cloud_volume.class, :detach_volume) + + payload = {:action => "detach", :resources => {:vm_id => vm.id.to_s}} + post(api_cloud_volume_url(nil, cloud_volume), :params => payload) + + expect(response).to have_http_status(:ok) + end + + it 'attach raise an error if the cloud volume does not support attach_volume' do + cloud_volume = FactoryBot.create(:cloud_volume_autosde) + stub_supports_not(:cloud_volumes, :attach_volume) + + api_basic_authorize(action_identifier(:cloud_volumes, :attach, :resource_actions, :post)) + + post(api_cloud_volume_url(nil, cloud_volume), :params => {:action => "attach"}) + expected = { + "success" => false, + "message" => a_string_including("Attach Volume for Cloud Volume id: #{cloud_volume.id} name: '': Feature not available\/supported") + } + expect(response.parsed_body).to include(expected) + expect(response).to have_http_status(:bad_request) + end + + it 'detach raise an error if the cloud volume does not support detach_volume' do + cloud_volume = FactoryBot.create(:cloud_volume_autosde) + stub_supports_not(:cloud_volumes, :detach_volume) + + api_basic_authorize(action_identifier(:cloud_volumes, :detach, :resource_actions, :post)) + + post(api_cloud_volume_url(nil, cloud_volume), :params => {:action => "detach"}) + expected = { + "success" => false, + "message" => a_string_including("Detach Volume for Cloud Volume id: #{cloud_volume.id} name: '': Feature not available\/supported") + } + expect(response.parsed_body).to include(expected) + expect(response).to have_http_status(:bad_request) + end end describe 'restore backup' do